Home > other >  React not rendering list after the state is changed
React not rendering list after the state is changed

Time:04-08

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). The items have a button which when clicked marks it into done state and vice-versa. 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, i.e. 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.

CodePudding user response:

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.

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.
  • Uses poor boolean comparisons to set a boolean value. You can either toggle a boolean or set the value to the result of a boolean expression.
  • 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.
  • Use the exercise id property as a React key and as the property used for toggling the completed (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>
  );
}

Edit react-not-rendering-list-after-the-state-is-changed

CodePudding user response:

try to add dependecies in useEffect

CodePudding user response:

The reason of your app not updating is because when your state changes react is not re-rendering it again.

so use useEffect, there are many hooks which can be used as per requirement.

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. You can also add multiple dependencies like [ state, pending, etc.. ];

Try on your own you'll understand it faster.

Hope hint will help you!

CodePudding user response:

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 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 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)
}
  • Related