首页 > 解决方案 > 从孩子到父母的反应钩子回调

问题描述

我有这个子组件称为TodoList

const TodoItem = ({ checked, children }) => 
   (<TouchableOpacity 
      style={{ backgroundColor: checked && 'red'}}>
      {children}
    </TouchableOpacity>
);

const TodoList = props => {
  const {
    options = [],
    onSelect,
    ...rest
  } = props;
  const [selectedOptionIndex, setSelectedOptionIndex] = useState(null);

  useEffect(() => {
    onSelect(options[selectedOptionIndex]);
  }, [onSelect, options, selectedOptionIndex]);

  const renderItem = (o, index) => {
    return (
      <TodoItem
        key={o + index}
        onPress={() => setSelectedOptionIndex(index)}
        checked={index === selectedOptionIndex}>
        {index === selectedOptionIndex && <Tick />}
        <Text>{o}</Text>
      </TodoItem>
    );
  };

  return (
    <View {...rest}>{options.map(renderItem)}</View>
  );
};

export default TodoList;

我有一个名为的父组件Container

export default function() {
  const [item, setItem] = setState(null);
  return (
    <Screen>
      <TodoList options={[1,2,3]} onSelect={(i) => setItem(i)} />
    </Screen>
  )
}

我希望在选择 aonSelect时使用从子组件到父组件的回调TodoItem。但是,每当onSelect调用时,我的TodoList重新渲染并且我selectedOptionIndex的被重置。因此,我的checked标志只会true在重置为false.

如果我删除onSelect回调,它工作正常。但我需要setState为孩子和父母。我怎么做?

标签: javascriptreactjsreact-hooks

解决方案


很难说出为什么会发生这种情况,很可能是因为容器的状态正在发生变化,导致一切都重新渲染。

不过,这样的事情应该可以帮助你。

const { render } = ReactDOM;
const { useEffect, useState } = React;

const ToDoItem = ({checked, label, onChange, style}) => {
  const handleChange = event => onChange(event);
  return (
    <div style={style}>
      <input type="checkbox" checked={checked} onChange={handleChange}/>
      {label}
    </div>
  );
}


const ToDoList = ({items, onChosen}) => {
  const [selected, setSelected] = useState([]);
  
  const handleChange = item => event => {
    let s = [...selected];
    s.includes(item) ? s.splice(s.indexOf(item), 1) : s.push(item);
    setSelected(s);
    onChosen(s);
  }
  
  return (
    <div>
      {items && items.map(i => {
        let s = selected.includes(i);
        return (
          <ToDoItem 
            key={i} 
            label={i} 
            onChange={handleChange(i)} 
            checked={s}
            style={{textDecoration: s ? 'line-through' : ''}}/>
        )
      })}
    </div>
  );
}

const App = () => {
  const [chosen, setChosen] = useState();
  const handleChosen = choices => {
    setChosen(choices);
  }
  return (
    <div>
      <ToDoList items={["Rock", "Paper", "Scissors"]} onChosen={handleChosen} />
      {chosen && chosen.length > 0 && <pre>Chosen: {JSON.stringify(chosen,null,2)}</pre>}
    </div>
  );
}

render(<App />, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>


推荐阅读