Компоненты, возвращенные из .map(), не загружаются в DOM

#reactjs

#reactjs

Вопрос:

Я пытаюсь загрузить некоторые компоненты в DOM после get выполнения вызова. Консоль подтверждает, что компоненты загружены в переменную, но DOM не обновляется. Есть ли проблема с синтаксисом

 const Blog: FC<BlogProps> = ({title, url}): ReactElement => {
    let response = [];
    let Posts = [];
    const {isDarkMode} = useContext(ThemeContext);
    function fetchBlogs(){
        let url = url;
        let count = 30;
        axios({
            method: 'post',
            url: '/api/grabIt',
            data: {
                url: url,
                count: count
            }
        })
            .then(function (res) {
                response = res.data.response;
                Posts = response.map(async function (item, i) {
                   return (<li><Post category={item.type} title={item.title} author={item.by} image={item.url} link={item.url} key={i}/></li>)
                })
            })
            .catch(function (error) {
                console.log(error)
            });
    }

    return (
        <>
            <div>
                <Button buttonColor={!!isDarkMode}
                        onClick={fetchBlogs}
                >FETCH</Button>
                <ul>
                    {Posts}
                </ul>
            </div>
        </>
    )
};

export default Blog
  

Я также попытался просто создать массив, который определяется при загрузке компонента (а не после), и DOM по-прежнему не обновляется. Я просто получаю пустое <ul>

Комментарии:

1. Почему функция внутри map асинхронна? Он возвращает обещание, а не экземпляр компонента.

2. Posts — это просто переменная, не имеющая отношения к состоянию компонента, React не знает, что ему нужно выполнить повторный запуск. измените сообщения, чтобы использовать React.useState

3. Вы могли бы добавить логику сопоставления внутри возврата и использовать состояния для его обновления. Есть ли причина избежать этого?

Ответ №1:

 
const Blog: FC<BlogProps> = ({ title, url }): ReactElement => {
    let response = [];
    const { isDarkMode } = useContext(ThemeContext);
    const [list, setList] = React.useState([]);
    function fetchBlogs() {
        let url = url;
        let count = 30;
        axios({
            method: 'post',
            url: '/api/grabIt',
            data: {
                url: url,
                count: count
            }
        })
            .then(function (res) {
                setList(res.data.response);
            })
            .catch(function (error) {
                console.log(error)
            });
    }

    return (
        <>
            <div>
                <Button buttonColor={!!isDarkMode}
                    onClick={fetchBlogs}
                >FETCH</Button>
                <ul>
                    {list.map((item, i) => {
                        return <li key={`row-${i}`}>
                            <Post category={item.type} title={item.title} author={item.by} image={item.url} link={item.url} key={i} />
                        </li>;
                    })}
                </ul>
            </div>
        </>
    )
};

export default Blog
  

Ответ №2:

Во-первых, при создании нескольких тегов вы должны добавить key к корневому элементу, который вы возвращаете.

Чтобы загрузить ваш список, вам нужно использовать useState для вашего массива Posts.

Ответ №3:

Posts это обычный массив, а не реактивный, в смысле React. Его изменение не вызовет повторной визуализации. Используйте useState , чтобы сделать это реактивной переменной. Вы также должны map проверять ответ синхронно, и на самом деле нет необходимости создавать компоненты здесь. Вместо этого сделайте это в инструкции return:

 const Blog: FC<BlogProps> = ({title, url}): ReactElement => {
  const [posts, setPosts] = React.useState([]);
  const {isDarkMode} = useContext(ThemeContext);

  function fetchBlogs() {
    axios({
      method: 'post',
        url: '/api/grabIt',
        data: { url, count: 30 }
      })
        .then(function (res) {
           if (res.data.response) {
             setPosts(res.data.response);
           }
        })
        .catch(function (error) {
            console.log(error)
        });
    }

  return (
    <>
      <div>
        <Button
          buttonColor={!!isDarkMode}
          onClick={fetchBlogs}
        >
          FETCH
        </Button>
        <ul>
          {posts.map((post, i) => (
            <li key={i}>
              <Post
                category={post.type}
                title={post.title}
                author={post.by}
                image={post.url}
                link={post.url} 
               />
            </li>
          )}
        </ul>
      </div>
    </>
  )
};

export default Blog;