从孩子到父母反应钩子回调

时间:2019-09-21 17:15:56

标签: javascript reactjs react-hooks

我有一个名为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>
  )
}

无论何时选择onSelect,我都希望使用TodoItem从子组件到父组件进行回调。但是,无论何时调用onSelect,我的TodoList都会重新呈现,而我的selectedOptionIndex被重置。因此,我的checked标志只会在重置为true之前短暂地变为false

如果我删除了onSelect回调,它将正常工作。但是我需要setState来照顾孩子和父母。我该怎么办?

2 个答案:

答案 0 :(得分:0)

很难说出为什么会发生这种情况,最有可能是因为容器的状态在变化,导致所有内容重新呈现。

但是这种事情应该可以帮到你。

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>

答案 1 :(得分:0)

原来,我的顶级组件Screen导致了此重新渲染。在我的Screen功能组件中,我在return

之前有这段代码
  const Content = scroll
    ? contentProps => {
        const { style: contentContainerStyle } = contentProps;
        return (
          <ScrollView {...contentContainerStyle}>
            {contentProps.children}
          </ScrollView>
        );
      }
    : View;

  return (
    <Content>{children}</Content>
  )

每当我的状态改变时,它都会以某种方式(不确定为什么)使孩子们重新渲染。 我通过删除函数对其进行了修复,并使其仅返回一个View

  const Content = scroll ? ScrollView : View;