简体   繁体   English

无法有条件地渲染组件

[英]Unable to render a component conditionally

I am trying to render a component conditionally based on parent's state.我正在尝试根据父级的 state 有条件地渲染组件。 But I am unable to do that.但我无法做到这一点。

In my current code, I am able to see component after "todos.length>0" but when I start to type in any text fields.在我当前的代码中,我可以在“todos.length>0”之后看到组件,但是当我开始输入任何文本字段时。

My parent component:我的父组件:

function App() {
  const [title,setTitle] = React.useState("")
  const [desc, setDesc] = React.useState("")
  const [todos, setTodos] = React.useState([])

  const titleChange = (e) => {
           const value=e.target.value;
           setTitle(value)
  }

  const descChange = (e) => {
           const value=e.target.value;
           setDesc(value)
  }

  const handleCancel = () => {
    setTitle("");
    setDesc("")
  }

  const handleAdd = () => {
    const newTodos = todos;
    newTodos.push({
      title:title,
      description: desc
    });
    setTodos(newTodos)
  }

  return (
    <div >
      <label>Enter Title</label>
      <TextField onChange={(e) => titleChange(e)} value={title} />
      <label>Description</label>
      <TextArea onChange={(e) => descChange(e)} value = {desc}/>
      <Button onClick={handleCancel}>Cancel</Button>
      <Button onClick={handleAdd}>ADD</Button>
<div>
      {todos.length && <TodoList todos={todos} />}
      </div>
    </div>
  );
}

My child component:我的子组件:

export default function TodoList (props){

    React.useEffect(() => {
      console.log("mounted")
    })

    return (
        <div>
        {console.log(props)}
        </div>
    )
}

Even, I tried using ternary operator like this,甚至,我尝试过像这样使用三元运算符,

todos.length ? <TodoList todos={todos} /> : null

I think you want to display to do list if some tasks in it如果其中有一些任务,我认为您想显示待办事项列表

todos.length > 0 ? <TodoList todos={todos} /> : null

Or you can do in this way或者你可以这样做

{ todos.lenght > 0 && <TodoList todos={todos} /> }

{ true && expression } returns expression { false && expression } return false { true && expression }返回expression { false && expression }返回false

Okay you are missing something, in your handleAdd function you are just pushing to the same array, this way React will have the same reference of the previous array so it will bail out of the state update, you should create a new array from the existing one Change your handleAdd as this好的,您遗漏了一些东西,在您的 handleAdd function 中,您只是推送到同一个数组,这样 React 将具有与前一个数组相同的引用,因此它将摆脱 state 更新,您应该从现有的数组创建一个新数组一 更改您的句柄添加为这样

const handleAdd = () => {
const newTodos = [ ...todos];
newTodos.push({
  title:title,
  description: desc
});
setTodos(newTodos)

} }

This way React will update the todos state, and change这样 React 将更新 todos state,并更改

{todos.length && <TodoList todos={todos} />}

to

{todos.length > 0 && <TodoList todos={todos} />}

one more thing in your child component instead of logging, get the size of array in div子组件中的另一件事,而不是记录,获取 div 中数组的大小

<div>
    {props.todos.length}
</div>

Hope it helps希望能帮助到你

Don't mutate state.不要突变 state。

Just correct your handleAdd function.只需更正您的手柄添加handleAdd

  const handleAdd = () => {
    setTodos([...todos, {title: title, description: desc }])
  };

Hope that helps!!!希望有帮助!!!

When component renders very first time todos length will always 0 .component第一次渲染时, todos length将始终0 So {todos.length && condition becomes false .所以{todos.length &&条件变为false

you should use something like that to avoid this issue:你应该使用类似的东西来避免这个问题:

{todos.length >0  && <TodoList todos={todos} />}  

I think your handleAdd function should look like this:我认为您的 handleAdd function 应该如下所示:

const handleAdd = () => {
   setTodos(todos => [...todos, { title: title, description: desc }]);
};

If the new state is computed using the previous state, you can pass a function to setState: https://reactjs.org/docs/hooks-reference.html#functional-updates If the new state is computed using the previous state, you can pass a function to setState: https://reactjs.org/docs/hooks-reference.html#functional-updates

This may not make a difference, but you don't need to create a function as value for onChange in your TextField components.这可能没有什么不同,但您不需要在 TextField 组件中创建 function 作为 onChange 的值。 onChange is going to pass event to your function unless your TextField component isn't handling that properly. onChange 会将事件传递给您的 function ,除非您的 TextField 组件没有正确处理。 In other words, the usage of the TextField components should look like this...换句话说,TextField 组件的用法应该是这样的......

<TextField onChange={titleChange} value={title} />

Your TextField component itself should be doing something like this...你的 TextField 组件本身应该做这样的事情......

function TextField({onChange}) {
    function handleChange(event) {
        // Pass the event as an argument into the onChange prop
        onChange(event) 
    }

    return <input onChange={handleChange} />
}

If your TextField component is a third party component, they do at least pass a value back as an argument so check that.如果您的 TextField 组件是第三方组件,它们至少会传递一个值作为参数,因此请检查这一点。

Another possibility is you are actually mutating todos in the handleAdd function.另一种可能性是您实际上是在 handleAdd function 中更改待办事项。 If you want to insure todos isn't mutated you can use the ES6 way of adding values to an array...如果你想确保 todos 不会发生变异,你可以使用 ES6 向数组添加值的方式......

function handleAdd() {
  setTodos([
    ...todos, 
    {
      title: title,
      description: desc
    }
  ])
}

If none of that helps console.log your todos state in the parent component and see if it is changing.如果这些都没有帮助 console.log 你的 todos state 在父组件中,看看它是否正在改变。

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

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