在子组件状态更改时,更新同级

时间:2019-09-05 16:26:27

标签: reactjs

部分工作的示例:https://codesandbox.io/s/jolly-smoke-ryb2d

问题: 当用户展开/打开组件行时,父组件行内的所有其他行都需要折叠。不幸的是,我似乎无法使其他同级行崩溃。

我尝试将处理程序从父级传递到子级,以更新父级的状态,然后将其传播到子级。

预期结果 在展开/打开一行时,折叠未单击的父组件中所有其他打开的行

代码:

App.tsx

import React from "react";
import ReactDOM from "react-dom";
import Rows from "./Rows";
import Row from "./Row";
import "./styles.css";

export interface AppProps {}

const App: React.FC<AppProps> = props => {
  return (
    <Rows>
      <Row>
        <p>Click me</p>
        <p>Collapse</p>
      </Row>
      <Row>
        <p>Click me</p>
        <p>Collapse</p>
      </Row>
      <Row>
        <p>Click me</p>
        <p>Collapse</p>
      </Row>
    </Rows>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Rows.tsx

Rows.tsx

import React, { useState, useEffect } from "react";
import Row, { RowProps } from "./Row";

export interface RowsProps {}

const Rows: React.FC<RowsProps> = props => {
  const [areRowsHidden, setAreRowsHidden] = useState<boolean>(false);

  useEffect(() => {});

  const handleOnShow = (): void => {};
  const handleOnCollapse = (): void => {};

  const renderChildren = (): React.ReactElement[] => {
    return React.Children.map(props.children, child => {
      const props = Object.assign(
        {},
        (child as React.ReactElement<RowsProps>).props,
        {
          onShow: handleOnShow,
          onCollapse: handleOnCollapse,
          isCollapsed: areRowsHidden
        }
      );
      return React.createElement(Row, props);
    });
  };

  return <>{renderChildren()}</>;
};

export default Rows;

Row.tsx

import React, { useState, useEffect } from "react";

export interface RowProps {
  onCollapse?: Function;
  onShow?: Function;
  isCollapsed?: boolean;
}

const Row: React.FC<RowProps> = props => {
  const [isCollapsed, setIsCollapsed] = useState(props.isCollapsed || true);

  useEffect(() => {}, [props.isCollapsed]);

  const handleClick = (): void => {
    if (isCollapsed) {
      props.onShow();
      setIsCollapsed(false);
    } else {
      props.onCollapse();
      setIsCollapsed(true);
    }
  };

  return (
    <>
      {React.cloneElement(props.children[0], {
        onClick: handleClick
      })}

      {isCollapsed ? null : React.cloneElement(props.children[1])}
    </>
  );
};

export default Row;

1 个答案:

答案 0 :(得分:0)

我将存储Rows.tsx中打开的哪一行,并将该值发送给其子级,而不是让子级控制该状态。您可能会看到这被称为提升状态。您可以详细了解here

Rows.tsx

import React, { useState } from 'react'
import Row from './Row'

export interface RowsProps {}

const Rows: React.FC<RowsProps> = props => {
  const [visibleRowIndex, setVisibleRowIndex] = useState<number>(null)

  const renderChildren = (): React.ReactElement[] => {
    return React.Children.map(props.children, (child, index) => {
      const props = Object.assign({}, (child as React.ReactElement<RowsProps>).props, {
        onShow: () => setVisibleRowIndex(index),
        onCollapse: () => setVisibleRowIndex(null),
        isCollapsed: index !== visibleRowIndex
      })
      return React.createElement(Row, props)
    })
  }

  return <>{renderChildren()}</>
}

export default Rows

Row.tsx

import React from 'react'

export interface RowProps {
  onCollapse?: Function
  onShow?: Function
  isCollapsed?: boolean
}

const Row: React.FC<RowProps> = props => {
  const handleClick = (): void => {
    if (props.isCollapsed) {
      props.onShow()
    } else {
      props.onCollapse()
    }
  }

  return (
    <>
      {React.cloneElement(props.children[0], {
        onClick: handleClick
      })}

      {props.isCollapsed ? null : React.cloneElement(props.children[1])}
    </>
  )
}

export default Row

示例:https://codesandbox.io/s/gifted-hermann-oz2zw

请注意:我注意到您正在克隆元素并执行通常称为prop drilling的操作。您可以通过使用context来避免这种情况,如果有兴趣的话,虽然不是必需的。