Реагировать на обратный вызов от дочернего к родительскому. - PullRequest
1 голос
/ 21 сентября 2019

У меня есть этот дочерний компонент с именем 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 голосов
/ 22 сентября 2019

Оказалось, что мой компонент верхнего уровня 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;
0 голосов
/ 21 сентября 2019

Трудно сказать, почему это происходит для вас, скорее всего потому, что состояние контейнера меняется, и все перерисовывается.

Однако что-то подобное должно вам помочь.

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

const ToDoItem = ({checked, label, onChange, style}) => {
  const handleChange = event => onChange(event);
  return (
    
      
      {label}
    
  );
}


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 (
    
      {items && items.map(i => {
        let s = selected.includes(i);
        return (
          
        )
      })}
    
  );
}

const App = () => {
  const [chosen, setChosen] = useState();
  const handleChosen = choices => {
    setChosen(choices);
  }
  return (
    
      
      {chosen && chosen.length > 0 && Chosen: {JSON.stringify(chosen,null,2)}
} );} render (, 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>
...