javascript 如何通过从子组件调用prop来重新呈现页面?

qvk1mo1f  于 2023-01-24  发布在  Java
关注(0)|答案(1)|浏览(113)

我认为当涉及到引起重新呈现时,我不理解状态的一些东西。当传递一个状态作为prop及其setState时,我希望我能够在调用setState时引起重新呈现,但这似乎不是事实。
我已经创建了一段代码来表达我的意思。下面的代码包含了一个简单的任务列表。你可以看到我已经将列表分成了4个部分,(标题、添加任务、更新所有任务、更新一天内任务)。输入任务名称时,task time和task day在按create new task后,任务将添加到任务状态。然后,这将被传递到第二层,在第二层中,任务将按天排序,然后将传递到最后一个子节点,该子节点将在下拉列表中列出此任务,通过单击天一侧的小胡萝卜可以展开该下拉列表。
我的目标是尝试创建一个系统,在那里我可以更新一个单独的任务,在某一天内关联的所有任务或列表中的所有任务。目前,我可以使用prop.setTask更新一天内的所有任务。如果我做了一些导致重新呈现的事情,如添加新任务,那么子组件将重新呈现渲染和去它应该去的地方,但如果我只改变所有的任务在一天内没有重新渲染发生,尽管调用我的props.setTask,我不知道为什么,因为我正在更新一个状态。有人能解释这是为什么吗?
请注意,我创建它只是为了更新一天内的所有任务,你可以通过在日期名称旁边的下拉菜单中选择一天来完成。每个级别都有颜色编码,以便更容易识别。

  • 浅蓝色=标题
  • 红色-添加任务
  • coral-更新所有任务
  • 浅灰色-一天内任务

重现问题的步骤

  • 创建任务
  • 在分配给任务的日期打开下拉列表
  • 使用日期名称旁边的下拉菜单更改任务日期
  • 问题:未调用重新渲染

Example Code
如果您需要任何澄清,我很乐意提供,尽管我认为这只是对状态生命周期的一些误解。
未加载沙箱中的代码

    • 应用程序js**
import './styleSheets/mainPage.css';
import {useState,useEffect} from 'react'
import AllTaskList from './components/AllTaskList'

function App() {

  const[task,setTask] = useState([])

  useEffect(()=>{
    console.log('task have updated')
    console.log(task)
  },[task])

  const clearAllTask = () =>{

    document.getElementById('task-name').value = ''
    document.getElementById('task-time').value = ''
    setTask([])

  }

  const createTask = () =>{

    let temp = {}
    let tempArr = []

    if(document.getElementById('task-name').value.length > 0 && document.getElementById('task-time').value.length > 0){

      try{
        temp.taskName = document.getElementById('task-name').value
        temp.taskTime = document.getElementById('task-time').value
        temp.taskDay = document.getElementById('task-date').value

        tempArr.push(temp)
        tempArr = task.concat(tempArr)
    
        setTask(tempArr)
      }catch{
        window.alert('It seems like you may have entered your values incorrectly please try again')
      }
  
    }else{
      window.alert('Please make sure all inputs are filled in.')
    }

  }
 
  return (
    <div className={'todo-list-all-container'}>
      <div className={'todo-list-header-container'}>
        <h className={'todo-list-all-header'}>TODO List</h>
      </div>

      <div className='todo-list-create-container'>
        <div className='todo-list-name-container'>
          <input id='task-name' placeholder='Enter Task Name' autoComplete={'off'}/>
        </div>

        <div className='todo-list-time-container'>
          <input id='task-time' placeholder='Enter Task Due Time' autoComplete={'off'}/>
        </div>

        <div className='todo-list-date-container'>
          <select name="days" id="task-date">
            <option value="Monday">Monday</option>
            <option value="Tuesday">Tuesday</option>
            <option value="Wednsday">Wednsday</option>
            <option value="Thursday">Thursday</option>
            <option value="Friday">Friday</option>
            <option value="Saturday">Saturday</option>
            <option value="Sunday">Sunday</option>
          </select>
        </div>

        <div className='create-task-button-container'>
          <button className='create-task-button' onClick={()=>{createTask()}}>Create New Task</button>
          <button onClick={()=>{clearAllTask()}} >Clear All Task</button>
        </div>

        <div className={'All-Task-List'}>
          <AllTaskList taskList = {task} setTask={setTask}/>
        </div>

      </div>

    </div>
  );
}

导出默认应用程序;

  • ./组件/所有任务列表. js*
import { useState,useEffect } from "react"
import WeekdayTable from './WeekdayTable'

export default function AllTaskList(props){

    let sortedTask = {Monday:[],Tuesday:[],Wednsday:[],Thursday:[],Friday:[],Saturday:[],Sunday:[]}
    let weekDays = ['Monday','Tuesday','Wednsday','Thursday','Friday','Saturday','Sunday']
    let task = props.taskList
    let blanketTaskDay = false

    useEffect(()=>{
        sortTask()
        console.log(sortedTask)
    },[props])

    const sortTask = () =>{

        if(Array.isArray(task)){

            for(let day = 0;day < weekDays.length;day++){
                for(let taskPos = 0;taskPos < task.length;taskPos++){
                    if(task[taskPos].taskDay == weekDays[day]){
                        sortedTask[weekDays[day]].push(task[taskPos])
                    }
                }
            }

        }else{
            console.log('did not detect array')
        }

    }

    const updateAllTaskDay = (e) =>{

        blanketTaskDay = e.target.value

    }

    const resetAllTaskDay = () =>{

        blanketTaskDay = false

    }

    return(
        <div className="all-week-days-sorted">
            <div className='week-day-table-container'>
                <div className='table-container-header'>
                    <p>This Weeks Task</p>
                </div>

                <div className="update-all-container">
                    <select name="days" id="task-date" onSelect={(e)=>{updateAllTaskDay(e)}}> 
                        <option value="Monday">Monday</option>
                        <option value="Tuesday">Tuesday</option>
                        <option value="Wednsday">Wednsday</option>
                        <option value="Thursday">Thursday</option>
                        <option value="Friday">Friday</option>
                        <option value="Saturday">Saturday</option>
                        <option value="Sunday">Sunday</option>
                    </select>
                </div>

                {weekDays.map((day)=>{
                    return <WeekdayTable 
                        weekList = {sortedTask[day]} 
                        weekDay = {day} updateDate = {blanketTaskDay} 
                        resetAllTaskDay = {resetAllTaskDay} 
                        task={props.taskList} 
                        setTask = {props.setTask}/>
                })}   

            </div>
        </div>
    )

}
  • ./组件/工作日表. js*
import {useState,useEffect} from 'react'

export default function WeekdayTable(props){

    const[open,setOpen] = useState()
    const toggleOpen = (val) =>{setOpen(val)}

    let todaysTask = props.weekList
    let day = props.weekDay
    let masterTask = props.task

    useEffect(()=>{

        

    },[props])

    const updateAllWeekDay = (e) =>{

        let temp = []

        for(let taskPos = 0;taskPos < todaysTask.length;taskPos++){
            for(let masterTaskPos = 0;masterTaskPos < masterTask.length;masterTaskPos++){
                if(todaysTask[taskPos].taskName == masterTask[masterTaskPos].taskName && todaysTask[taskPos].taskDay == masterTask[masterTaskPos].taskDay){
                    masterTask[masterTaskPos].taskDay = e.target.value
                }
            }
        }

        props.setTask(masterTask)

    }

    return(
        <div className={'day-wrapper'}>

                <div className = {'dd-header--bold'} id={day+'-dd-header--bold'}>
                    <p>{day}</p>
                </div>
                
                <div className={'update-day'} id={day+'-update-day'} onChange={(e)=>{updateAllWeekDay(e)}}>
                    <select name="days" id="task-date">
                            <option value="Monday">Monday</option>
                            <option value="Tuesday">Tuesday</option>
                            <option value="Wednsday">Wednsday</option>
                            <option value="Thursday">Thursday</option>
                            <option value="Friday">Friday</option>
                            <option value="Saturday">Saturday</option>
                            <option value="Sunday">Sunday</option>
                        </select>
                </div>

                <div className='embedded-dd-header__action'>
                    <p onClick={()=>{toggleOpen(!open)}}>{open ? '^' : '⌄'}</p>
                </div>

                {open && (
                    todaysTask.map(task=>{
                        return(
                            <table>
                                <tr className={'task-val-row'}>
                                    <td className={'task-val'}>
                                        <input defaultValue = {task.taskName}></input>
                                    </td>
                                    <td className={'task-val'}>
                                        <input defaultValue = {task.taskTime}></input>
                                    </td>
                                    <td className={'task-val'}>
                                        <input id={task.taskName+task.taskDay+'-task-day'} defaultValue = {task.taskDay}/>
                                    </td>
                                </tr>
                            </table>
                        )
                    })
                )}

        </div>
    )

}
  • ./样式表/主页面. css*
.todo-list-all-container{
    background-color: aqua;
}

.todo-list-header-container{
    text-align: center;

}

.todo-list-create-container{
    text-align: center;
    background-color: red;
}

.All-Task-List{
    background-color: lightcoral;
}

.table-container-header{
    display: inline-block;
}

.update-all-container{
    display:inline-block;
}

.day-wrapper{
    background-color: lightcyan;
}

.dd-header--bold{
    display: inline-block;
    padding-right: 1%;
}

.update-day{
    display: inline-block;
    padding-right: 1%;
}

.embedded-dd-header__action{
    display: inline-block;
}

.table{
    border:1px solid black;
}

.task-val-row{
    text-align: center;
    border:1px solid black;
}

.task-val{
    text-align: center;
    border:1px solid black;
}
zujrkrfu

zujrkrfu1#

看起来React的一些基本规则被忽视了。

  • 属性应用作只读值
  • 始终将新对象传递给状态设置器
  • 不要直接改变状态

此外,select元素没有与之关联的onSelect事件,两个可用事件是inputchange

export default function WeekdayTable(props) {
  // ...
  let masterTask = props.task;

  const updateAllWeekDay = (e) => {

    props.setTask(masterTask); // <= You are using the same object reference 
    // as the new state, thus React will compare the previous reference
    // with the one you pass to setTask, the equality check on the previous 
    // and next state values will return true since they are the
    // same object, hence no re-render will occur

    // To trigger a re-render, you must respect the rules of React: 
    // always return a new object as a value passed to the setState methods:
    props.setTask([...masterTask])

    // Also, inside the updateAllWeekDay, you should NOT be mutating the masterTask 
    // which was passed as a prop
    // Props are meant to be treated as read-only values
    // Work on a copy of the prop, e.g.
    let masterTask = [...props.task];
    masterTask.push( something );
    etc.

  };
  ...

相关问题