最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - State is reverting to it's initial state even after calling state updater function - Stack Overflow

programmeradmin1浏览0评论

The code written below is from the functionality file, I was building a notes app and wanted to add a folder option too to categorize all the notes but while displaying the changing/adding notes to a folder I find that the folder_files state is getting updated after caling the add case of handleFileAddition function but when I re-call the function the state updation that was done on the previous call always gets replaced with the initialized value of it i.e. I am adding a checked property to all notes stored in noteList state so that I can check/uncheck them using this:-

{folder_files.map(note => {
  return 
    <>
      <label
        htmlFor={`note-${note.id}`}
        className='note'
        style={{ display: 'block', position: 'relative' }}
      >
        {note.para}
        <input
          type="checkbox"
          checked={note.checked}
          name={`note-${note.id}`}
          id={`note-${note.id}`}
          onChange={(e)=> handleFileAddition({
            type: "add",
            val: {
              id: note.id,
              check: e.target.checked
            }
          })}
          style={{
            position: 'absolute',
            right: 0,
            backgroundColor: "inherit"
          }}
        />
      </label>
    </>
  }
)}

Also due to folder_files not retaining the updated state it's making the input checkboxes not retain their check functionality.

Below is the whole functionality of folder part of my Notes App:

function useFunctionality() {
  const initialArr = []; // INITIAL ARRAY BEING ASSIGNED TO REDUCER HOOK

  // CHOOSING DISPLAY BETWEEN FILES & FOLDER
  const [choices, setChoices] = useState({
    files: true,
    folder_files: false,
    choice: false,
    change: {
      val: false,
      id: '',
      para: '',
      files: []
    }
  });

  // FOR HOLDING THE FOLDERS & THE FILE SUPPOSED TO BE STORED IN THEM
  const [folders, dispatchFolders] = useReducer(reducerFolder, initialArr);

  // STATE FOR HOVERING, RIGHT CONTAINER'S CHILDREN DISPLAY & 
  // NEW NOTE ADDITION FUNCTIONALITY
  const [isChanging, setIsChanging] = useState({
    hover: false,
    r_empty: false,
    add: false,
    change: {
      val: false,
      inp: '',
      txt:'',
      id: null
    }
  });

  // REDUCER HOOK FOR ADDITION, CHANGE & DELETION OF NOTES
  const [noteList, dispatch] = useReducer(reducer, initialArr); 

  // FILES WITH THE CHECKED PROPERTY ADDED 
  const [folder_files, setFolderFiles] = useState([])

  const inputRef = useRef(''); // REF FOR INPUT FIELD(FOR FILES & FOLDERS)
  const textRef = useRef(''); // REF FOR TEXT AREA(FOR FILES ONLY)
  let files;
  // let vg;

  // REPRESENTING CHANGE HERE UPDATED STATE IS GETTING SHOWN
  useEffect(() => {
    console.log(
      folder_files,
      choices.change,
      folder_files.filter(file => file.checked)
    )
  }, [folder_files])

  function idGenerator(notes) { // NOTE'S ID GENERATOR
    const arr = [...notes];
    const result = arr.length !== 0 ? arr[arr.length -1].id + 1 : 1
    return result;
  }

  function paraGenerator(inp, txt) { // GENERATING NOTES ENTRY FOR DISPLAY
    let para;
    switch(true) {
      case (inp && txt !== '' ):
        para = inp.slice(0, 15);
        break;

      case ((inp || txt) !== '' ):
        para = inp !== '' ? inp.slice(0, 15) : txt.slice(0, 15);
        break;

      default:
        para = null;
        break;
    }
    console.log(para, inp, txt)
    return para;
  }

  // DISPLAYING FOLDER NAMES OR THE EDITABLE SIDE
  function handleFolderDisplay(
    save = false,
    changer = false,
    value
  ) {
    if (changer) {
      setIsChanging({ ...isChanging, r_empty: true });
      setChoices({
        ...choices,
        change: {
          val: true,
          id: value.id,
          para: value.para,
          files: [value.folder_files]
        }
      })
    } else {
      if (!save) {
        const idFold = idGenerator(folders);
        setIsChanging({ ...isChanging, r_empty: true });
        setChoices({
          ...choices,
          change: {
            val: false,
            id: idFold,
            para: '',
            files: []
          }
        })
      } else {
        setIsChanging({ ...isChanging, r_empty: false });
        const para = paraGenerator(inputRef.current.value, '');
        if (choices.change.val) {
          setChoices({
            ...choices,
            change: {
              val: false,
              id: '',
              para: ''
            }
          });
          dispatchFolders({
            type: "change",
            values: {
              id: choices.change.id,
              para: inputRef.current.value
            }
          }) 
        } else {
          dispatchFolders({
            type: "add",
            values: {
              id: "fold" + choices.change.id,
              para: para,
              files: files
            }
          });
        }
      }
    }
  }

  // THE PROBLEM CODE BLOCK 
  function handleFileAddition(obj{
    let ff;
    switch (obj.type) {
      case "display":
        setChoices({ ...choices, folder_files: obj.val })
        break;

      case "add":
        console.log(folder_files, obj.val.check)
        setFolderFiles(prevFolderFiles => prevFolderFiles.map(file => {
          if (file.id === obj.val.id) {
            console.log(
              "got it",
              folder_files,
              file.checked,
              obj.val.check
            );
            try {
              return { ...file, checked: obj.val.check };
            } catch {
              console.log("Error")
            }
          } else {
            console.log("gt", file)
            return file;
          }
        }));
        break;

      case "save" : 
        setChoices({ ...choices, folder_files: obj.val })
        if (choices.change.val) {
          dispatchFolders({
            type: "file_change",
            id: choices.change.id,
            files: folder_files.filter(file=> file.checked)
          });
          setFolderFiles(folder_files.map(file => {
            return { ...file, checked: false }
          }))
        }
    }
  }

  function handleFolderDeletion(taskId) { 
    dispatchFolders({ type: "delete", id: taskId });
  }

  function handleChoices(choiceVal = true, files = choices.files) {
    choices.files === files
      ? null
      : setIsChanging({ ...isChanging, r_empty: false });
    setChoices(prevChoices => ({
      ...prevChoices,
      files: files, // Directly set based on files argument
      choice: choiceVal  // Update choice accordingly
        ? !prevChoices.choice
        : false,
    }));
    const arr = noteList.map(note => note.checked = false)
    setFolderFiles(noteList.map(note => {
      return { ...note, checked: false }
    }))
  }
    
  return {
    isChanging,
    choices,
    inputRef,
    textRef,
    noteList,
    folders,
    folder_files,
    handleChanging,
    dispatch,
    handleEmptiness,
    handleDeletion,
    handleChoices,
    handleFolderDisplay,
    handleFolderDeletion,
    handleFileAddition
  }
}

I was expecting the files to display checked state of theirs but they were not displaying it because of the folder_files retaining their initial state instead of updated state.

The code written below is from the functionality file, I was building a notes app and wanted to add a folder option too to categorize all the notes but while displaying the changing/adding notes to a folder I find that the folder_files state is getting updated after caling the add case of handleFileAddition function but when I re-call the function the state updation that was done on the previous call always gets replaced with the initialized value of it i.e. I am adding a checked property to all notes stored in noteList state so that I can check/uncheck them using this:-

{folder_files.map(note => {
  return 
    <>
      <label
        htmlFor={`note-${note.id}`}
        className='note'
        style={{ display: 'block', position: 'relative' }}
      >
        {note.para}
        <input
          type="checkbox"
          checked={note.checked}
          name={`note-${note.id}`}
          id={`note-${note.id}`}
          onChange={(e)=> handleFileAddition({
            type: "add",
            val: {
              id: note.id,
              check: e.target.checked
            }
          })}
          style={{
            position: 'absolute',
            right: 0,
            backgroundColor: "inherit"
          }}
        />
      </label>
    </>
  }
)}

Also due to folder_files not retaining the updated state it's making the input checkboxes not retain their check functionality.

Below is the whole functionality of folder part of my Notes App:

function useFunctionality() {
  const initialArr = []; // INITIAL ARRAY BEING ASSIGNED TO REDUCER HOOK

  // CHOOSING DISPLAY BETWEEN FILES & FOLDER
  const [choices, setChoices] = useState({
    files: true,
    folder_files: false,
    choice: false,
    change: {
      val: false,
      id: '',
      para: '',
      files: []
    }
  });

  // FOR HOLDING THE FOLDERS & THE FILE SUPPOSED TO BE STORED IN THEM
  const [folders, dispatchFolders] = useReducer(reducerFolder, initialArr);

  // STATE FOR HOVERING, RIGHT CONTAINER'S CHILDREN DISPLAY & 
  // NEW NOTE ADDITION FUNCTIONALITY
  const [isChanging, setIsChanging] = useState({
    hover: false,
    r_empty: false,
    add: false,
    change: {
      val: false,
      inp: '',
      txt:'',
      id: null
    }
  });

  // REDUCER HOOK FOR ADDITION, CHANGE & DELETION OF NOTES
  const [noteList, dispatch] = useReducer(reducer, initialArr); 

  // FILES WITH THE CHECKED PROPERTY ADDED 
  const [folder_files, setFolderFiles] = useState([])

  const inputRef = useRef(''); // REF FOR INPUT FIELD(FOR FILES & FOLDERS)
  const textRef = useRef(''); // REF FOR TEXT AREA(FOR FILES ONLY)
  let files;
  // let vg;

  // REPRESENTING CHANGE HERE UPDATED STATE IS GETTING SHOWN
  useEffect(() => {
    console.log(
      folder_files,
      choices.change,
      folder_files.filter(file => file.checked)
    )
  }, [folder_files])

  function idGenerator(notes) { // NOTE'S ID GENERATOR
    const arr = [...notes];
    const result = arr.length !== 0 ? arr[arr.length -1].id + 1 : 1
    return result;
  }

  function paraGenerator(inp, txt) { // GENERATING NOTES ENTRY FOR DISPLAY
    let para;
    switch(true) {
      case (inp && txt !== '' ):
        para = inp.slice(0, 15);
        break;

      case ((inp || txt) !== '' ):
        para = inp !== '' ? inp.slice(0, 15) : txt.slice(0, 15);
        break;

      default:
        para = null;
        break;
    }
    console.log(para, inp, txt)
    return para;
  }

  // DISPLAYING FOLDER NAMES OR THE EDITABLE SIDE
  function handleFolderDisplay(
    save = false,
    changer = false,
    value
  ) {
    if (changer) {
      setIsChanging({ ...isChanging, r_empty: true });
      setChoices({
        ...choices,
        change: {
          val: true,
          id: value.id,
          para: value.para,
          files: [value.folder_files]
        }
      })
    } else {
      if (!save) {
        const idFold = idGenerator(folders);
        setIsChanging({ ...isChanging, r_empty: true });
        setChoices({
          ...choices,
          change: {
            val: false,
            id: idFold,
            para: '',
            files: []
          }
        })
      } else {
        setIsChanging({ ...isChanging, r_empty: false });
        const para = paraGenerator(inputRef.current.value, '');
        if (choices.change.val) {
          setChoices({
            ...choices,
            change: {
              val: false,
              id: '',
              para: ''
            }
          });
          dispatchFolders({
            type: "change",
            values: {
              id: choices.change.id,
              para: inputRef.current.value
            }
          }) 
        } else {
          dispatchFolders({
            type: "add",
            values: {
              id: "fold" + choices.change.id,
              para: para,
              files: files
            }
          });
        }
      }
    }
  }

  // THE PROBLEM CODE BLOCK 
  function handleFileAddition(obj{
    let ff;
    switch (obj.type) {
      case "display":
        setChoices({ ...choices, folder_files: obj.val })
        break;

      case "add":
        console.log(folder_files, obj.val.check)
        setFolderFiles(prevFolderFiles => prevFolderFiles.map(file => {
          if (file.id === obj.val.id) {
            console.log(
              "got it",
              folder_files,
              file.checked,
              obj.val.check
            );
            try {
              return { ...file, checked: obj.val.check };
            } catch {
              console.log("Error")
            }
          } else {
            console.log("gt", file)
            return file;
          }
        }));
        break;

      case "save" : 
        setChoices({ ...choices, folder_files: obj.val })
        if (choices.change.val) {
          dispatchFolders({
            type: "file_change",
            id: choices.change.id,
            files: folder_files.filter(file=> file.checked)
          });
          setFolderFiles(folder_files.map(file => {
            return { ...file, checked: false }
          }))
        }
    }
  }

  function handleFolderDeletion(taskId) { 
    dispatchFolders({ type: "delete", id: taskId });
  }

  function handleChoices(choiceVal = true, files = choices.files) {
    choices.files === files
      ? null
      : setIsChanging({ ...isChanging, r_empty: false });
    setChoices(prevChoices => ({
      ...prevChoices,
      files: files, // Directly set based on files argument
      choice: choiceVal  // Update choice accordingly
        ? !prevChoices.choice
        : false,
    }));
    const arr = noteList.map(note => note.checked = false)
    setFolderFiles(noteList.map(note => {
      return { ...note, checked: false }
    }))
  }
    
  return {
    isChanging,
    choices,
    inputRef,
    textRef,
    noteList,
    folders,
    folder_files,
    handleChanging,
    dispatch,
    handleEmptiness,
    handleDeletion,
    handleChoices,
    handleFolderDisplay,
    handleFolderDeletion,
    handleFileAddition
  }
}

I was expecting the files to display checked state of theirs but they were not displaying it because of the folder_files retaining their initial state instead of updated state.

Share Improve this question edited 2 days ago Drew Reese 203k17 gold badges236 silver badges268 bronze badges asked 2 days ago Aman KaushikAman Kaushik 12 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

I think you're missing the key prop in list rendering.

{folder_files.map(note=>{
    return <Fragment key={note.id}> // provide key
        <label htmlFor={`note-${note.id}`}  className='note' style={{display: 'block', position : 'relative'}} >
            {note.para}<input type="checkbox" checked={note.checked} name={`note-${note.id}`} id={`note-${note.id}`} onChange={(e)=> handleFileAddition({type : "add", val : {id : note.id, check : e.target.checked}})} style={{position : 'absolute', right: 0, backgroundColor : "inherit"}}/>
        </label>
    </Fragment>
})}
发布评论

评论列表(0)

  1. 暂无评论