简体   繁体   English

更改 state 后反应不渲染列表

[英]React not rendering list after the state is changed

I am creating a simple tracker which records all the activities done.我正在创建一个简单的跟踪器,用于记录所有已完成的活动。 It is my first project in react.这是我的第一个反应项目。 I have created three state one for storing all the items(name of state is list), one for pending items(name of state is pending), one for completed items(name of state is completed).我创建了三个 state 一个用于存储所有项目(名称 state 是列表),一个用于待处理项目(名称 state is pending),一个用于完成项目(名称 state 已完成)。 The items have a button which when clicked marks it into done state and vice-versa.这些项目有一个按钮,单击该按钮会将其标记为完成 state,反之亦然。 It is completely rendering items for main list.它正在完全渲染主列表的项目。 But for other two its not rendering.但对于其他两个,它没有渲染。 When I am checking with react developer tools, it is working fine, ie it is adding to pending list or completed list as it should.当我检查反应开发人员工具时,它工作正常,即它正在添加到待定列表或完成列表中。 But it is not compiling them on screen.但它不是在屏幕上编译它们。 list is already filled with items.列表中已经填满了项目。 I have added all the code for just in case.为了以防万一,我添加了所有代码。

function Filters(props){
  const [completed, setCompleted] = useState([]);
  const [pending, setPending] = useState([]);
  const [state, setState] = useState("None");
  const [list,setList] = useState([]);

  function viewState(){
    setState("View-all");
  }

   //it is getting the clicked item id and marking it complete in main list
  function markComplete(id){
    list.map((items,index)=>{
      if(index===id){
        if(items.done===true)
          items.done = false;
        else{
          items.done=true;
        }
      }
    })
  }

//i am simply scanning the main list and the items which are pending will be added to this list. //this happens whenever the person click on pending button
 function pendingState(){
    setState("pending-all");
    setPending([]);
    list.map(items=>{
      if(items.done!==true){
        setPending(prev=>{
          return [...prev,items];
        })
      }
    })
  }

  function completedState(){
    setState("completed-all");
    setCompleted([]);
    list.map(items=>{
      if(items.done===true){
        setCompleted(prev=>{
          return [...prev,items];
        })
      }
    })
  }

 return (
    <div>
      <div className="input-section">
        <Note setList={setList} />
      </div>
      <button type="button" onClick={viewState} >View All</button>
      <button type="button" onClick={completedState}>Completed</button>
      <button type="button" onClick={pendingState}>Pending</button>
      <div>
        {
          (()=>{
            if(state==="View-all")
            {
              return (
                <div>
                  <h1>Working {completed}</h1>
                  {(list).map((items,index)=>
                    {
                    return (

                      <Excercise
                        key={index}
                        id={index}
                        title={items.name}
                        list={props.list}
                        setList={props.setList}
                        content={items.desp}
                        markComplete={markComplete}
                        />
                    )
                  })}
                </div>
              )
            }
            else if(state==="completed-all")
            {
              return (
                <div>
                {completed.map((items,index)=>{
                  <Excercise
                    key={index}
                    id={index}
                    title={items.name}
                    list={props.list}
                    setList={props.setList}
                    content={items.desp}
                    markComplete={markComplete}
                    />
                })}
                </div>
              )
            }
  })()
        }

      </div>


    </div>);
}



Kindly help.请帮忙。 Thank you.谢谢你。

Hi @DREW The function code:嗨@DREW function 代码:

  function markComplete(id){
    setList(lists=>{
      lists.map(item=>{
      return item.id===id ?{...item,done: !item.done} : (item);})
      }
      )
  }

When I am using it instead of当我使用它而不是

 const markComplete = (id) => {
    setList((list) =>
      list.map((item) =>
        item.id === id
          ? {
              ...item,
              done: !item.done
            }
          : item
      )
    );
  };

it is showing, "Cannot read properties of undefined (reading 'filter')" arent the both same.它显示,“无法读取未定义的属性(读取‘过滤器’)”两者并不相同。 If not, what am I doing wrong.如果不是,我做错了什么。 Sorry for bugging so many times, I have just started with react.抱歉打扰了这么多次,我刚刚开始使用 React。

I think you've overcomplicated things a bit.我认为你把事情复杂化了一点。 You only need one array to store the exercises in, the "pending" and "completed" states are easily derived from the list state and the state filter state value.您只需要一个数组来存储练习,“待定”和“已完成”状态很容易从list state 和state过滤器 state 值中导出。

Issues问题

  • markComplete callback is mutating the list state. When updating the list state not only is a new array reference necessary, but also new element object references are necessary for the elements that are being updated. markComplete回调正在改变list state。当更新list state 时,不仅需要新的数组引用,而且新元素 object 引用对于正在更新的元素也是必需的。
  • Uses poor boolean comparisons to set a boolean value.使用较差的 boolean 比较来设置 boolean 值。 You can either toggle a boolean or set the value to the result of a boolean expression.您可以切换 boolean 或将值设置为 boolean 表达式的结果。
  • Use the viewState , pendingState , and completedState handlers to simply set the filter value, and then derive the computed state when rendering by adding an inline filter function.使用viewStatependingStatecompletedState处理程序来简单地设置过滤器值,然后在渲染时通过添加内联filter function 派生计算出的 state。
  • Use the exercise id property as a React key and as the property used for toggling the completed ( done ) state.使用 exercise id属性作为 React 键用于切换完成 ( done ) state 的属性。

Solution解决方案

function Filters(props) {
  const [state, setState] = useState("None");
  const [list, setList] = useState([
    ...
  ]);

  function viewState() {
    setState("View-all");
  }

  function pendingState() {
    setState("pending-all");
  }

  function completedState() {
    setState("completed-all");
  }

  const markComplete = (id) => {
    setList((list) =>
      list.map((item) =>
        item.id === id
          ? {
              ...item,
              done: !item.done
            }
          : item
      )
    );
  };

  return (
    <div>
      <div className="input-section">
        <Note setList={setList} />
      </div>
      <button type="button" onClick={viewState}>
        View All
      </button>
      <button type="button" onClick={completedState}>
        Completed
      </button>
      <button type="button" onClick={pendingState}>
        Pending
      </button>
      <div>
        {list
          .filter((item) => {
            if (state === "pending-all") {
              return !item.done;
            } else if (state === "completed-all") {
              return item.done;
            }
            return true;
          })
          .map((item) => (
            <Excercise
              key={item.id}
              id={item.id}
              done={item.done}
              title={item.name}
              content={item.desp}
              markComplete={markComplete}
            />
          ))}
      </div>
    </div>
  );
}

在状态更改后编辑 react-not-rendering-list

try to add dependecies in useEffect尝试在useEffect中添加依赖

in this function you are mutating a state, so in order to do so you need to use the setState function, in this case, it will be setList().在这个 function 中,你正在改变一个 state,所以为了这样做你需要使用 setState function,在这种情况下,它将是 setList()。

 function markComplete(id){
    list.map((items,index)=>{
      if(index===id){
        if(items.done===true)
          items.done = false;
        else{
          items.done=true;
        }
      }
    })
  }

So a better way to implement this function could be, and remember, everything time you need to update a state you don't want to change the state directly, instead, you should make a copy and set the state to that copy因此,实现此 function 的更好方法可能是,请记住,每次您需要更新 state 时,您不想直接更改 state,相反,您应该制作一个副本并将 state 设置为该副本

function markComplete(id){
  const newList = [...list];

  newList.map((items,index)=>{
      if(index===id){
        if(items.done===true)
          items.done = false;
        else{
          items.done=true;
        }
      }
  }
  setList(newList)
}

The reason of your app not updating is because when your state changes react is not re-rendering it again.您的应用程序未更新的原因是因为当您的 state 更改反应时不会再次重新呈现它。

so use useEffect , there are many hooks which can be used as per requirement .所以使用useEffect有很多钩子可以根据需要使用

try putting this line of code尝试把这行代码

useEffect( ( ) => {
  
   console.log( 'Check console' );

}, [ dependency_here ] );

in dependency_here try adding state , completed , pending one by one and see the result.dependency_here尝试添加statecompletedpending一个一个地看结果。 You can also add multiple dependencies like [ state, pending, etc.. ] ;您还可以添加多个依赖项,例如[ state, pending, etc.. ]

Try on your own you'll understand it faster.自己尝试一下,您会更快地理解它。

Hope hint will help you!希望提示能帮到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM