programing

반응 - 여러 참조 전달

starjava 2023. 3. 8. 20:31
반응형

반응 - 여러 참조 전달

인접 html 테이블(InfoTable) 내의 대응하는 헤더로 스크롤해야 하는 동적으로 생성된 링크를 포함하는 SideNav 컴포넌트가 있습니다.나는 이것을 이루기 위해 여러 가지 다른 방법을 시도해봤지만 소용이 없었다.

export default class Parent extends Component {
  state = {
    categories: [],
  }

  scrollToHeader = (tableRefString) => {
    // Function to pass to SideNav to access refs in InfoTable
    this[tableRefString].scrollIntoView({ block: 'start' });
  }

  render() {
    return (
      <div>
        <SideNav
          categories={this.state.categories}
          scrollToHeader={this.scrollToHeader} />
        <InfoTable
          categories={this.state.categories} />
      </div>
    );
  }
}

export default class InfoTable extends Component {
  render() {
    return (
      <div>
        <table>
          <tbody>
            {this.props.categories.map(category => (
              <>
                // Forward the ref through InfoTableHeader to be set on the parent DOM node of each InfoTableHeader
                <InfoTableHeader />
                {category.inputs.map(input => <InfoTableRow />)}
              </>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}

SideNav에서 링크를 클릭하여 InfoTable에서 대응하는 헤더로 스크롤하려면 카테고리 배열의 이름을 기반으로 부모 상에서 동적으로 작성된 참조를 전송하고 이러한 참조를 InfoTable의 각 헤더에 대해 DOM 노드에 설정해야 합니다.여기서부터 SideNav로 이동하여 헤더까지 스크롤할 수 있는 기능을 Parent의 ref에 액세스 할 수 있습니다.

  • 여러 참조를 InfoTable 컴포넌트로 한 번에 전송하려면 어떻게 해야 합니까?
  • 제가 하려는 일을 더 깔끔하게 해낼 수 있는 방법이 있을까요?React.findDOMNode()에 대해 알아보았지만 참조가 더 나은 옵션인 것 같습니다.

이미 받아들여진 답변이 있다는 것을 알고 있지만, @nicholas-haley의 솔루션은 받아들일 수 있습니다.더 좋은 방법은 빌트인을 사용하는 것입니다.useImperativeHandle

중요: React Hooks API는 현재 제공되고 있습니다.

  • react@16.8.0 이후
  • react-displays@0.59.0 이후

React hooks API Docs 상태는 다음과 같습니다.

useImperativeHandle는 ref를 사용할 때 상위 컴포넌트에 노출되는 인스턴스 값을 사용자 정의합니다.은 forwardRefuseImperativeHandle 'forwardRef'와 함께.

이 주의에는 다음 예가 뒤따릅니다.

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

때문에 제가 때 더 이 될 것 같습니다.useImperativeHandle

이렇게 하면 특별한 ref 구문이 필요하지 않으며 컴포넌트는 단순히 특정 유형의 FatherRef를 반환할 수 있습니다.예:

// LabelInput.js
function LabelInput(props, ref) {
    const labelRef = useRef();
    const inputRef = useRef();

    useImperativeHandle(ref, () => ({
      focus: () => {
       inputRef.current.focus();
      },
      get input() {
          return inputRef.current;
      },
      get label() {
          return labelRef.current;
      },
      // ... whatever else one may need
    }));
    return (
      <div>
        <label ref={labelRef} ... />
        <input ref={inputRef} ... />;
      </div>
    )
}
LabelInput = forwardRef(LabelInput);

function MyScreen() {
   const labelInputRef = useRef();

   const onClick = useCallback(
    () => {
//       labelInputRef.current.focus(); // works
//       labelInputRef.current.input.focus(); // works
// ... etc
    },
    []
   );

   return (
     ...
      <LabelInput ref={labelInputRef} ... />
     ....
   )
}

비슷한 상황에서 여러 명의 레퍼런스를 부모 컴포넌트의 자녀에게 전송해야 했습니다.

해결책을 해, 할 수 .forwardRef★★★★

// Parent
ref={{
    ref1: this.ref1,
    ref2: this.ref2
}}

// Child
export default React.forwardRef((props, ref) => {
  const { ref1, ref2 } = ref;

  return (
    <Child1
      {...props}
      ref={ref1}
    />
    <Child2
      {...props}
      ref={ref2}
    />
  );
});

는 여기 붙이는 좋아하지 않습니다.refrefs할 수 있습니다.) 라고 말합니다.

편집:

2020년에는 @samer-murad의 답변이 이 문제에 대한 최선의 해결책이라고 생각합니다.

리액트 폼에서 이것을 집어들었습니다만, 레퍼런스를 공유해, 동시에 복수의 레퍼런스를 할당할 수 있는 좋은 방법을 제시했습니다.

<input name="firstName" ref={(e) => {
  register(e) // use ref for register function
  firstNameRef.current = e // and you can still assign to ref
}} />

난 아직도 그 안에서 무슨 일이 벌어지는지 모르겠어ref속성. 단, 다음과 같습니다.Reactsource code type of type.type === 'function' + 기타 답변으로 인해 다음 테스트를 통과했습니다.functionhoisted refs부터parent, 그리고 효과가 있습니다!

class Child extends React.Component {
  render() {
    return (
      <div>
        <div
          ref={this.props.pa}
          style={this.props.style}
          onClick={async () => {
            this.storeAuth(...this.props.storableAuth);
            this.props.clearStore();
          }}
        />
        <div
          ref={this.props.fwd}
          style={this.props.style}
          onClick={async () => {
            this.props.onStart();
            const res = await this.getUserInfo(verbose, auth, storedAuth);
            if (res === "login?") this.props.onPromptToLogin();
            if (res) this.props.onFinish(); //res.isAnonymous
          }}
        />
      </div>
    );
  }
}

export default React.forwardRef((props, getRefs) => {
  const { pa, fwd } = props.getRefs();
  return <Child fwd={fwd} pa={pa} {...props} />;
});


class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.pa = React.createRef();
    this.fwd = React.createRef();
  }
  render() {
    return (
      <Child
        getRefs={() => {
          return {
            pa: this.pa,
            fwd: this.fwd
          };
        }}
        storableAuth={this.state.storableAuth}//[]
        clearAuth={() => this.setState({ storableAuth: null })}
      />
    );
  }
}

이 질문의 작성자가 질문한 내용은 아니지만, 이 제목도 이 질문의 발단이 될 수 있습니다.React 컴포넌트를 사용하는 개발자가 내 컴포넌트에 내부 참조를 통과했을 때 참조를 통과하도록 허용하는 방법(즉, 이 컴포넌트에 대한 참조를 여러 개 통과시키는 방법)입니다.

이것이 제가 가지고 온 해결책입니다.

import { useState, useRef } from "react";

export default function App() {
  const [, render] = useState({});
  const reRender = () => render({});

  const divRef = useRef();
  console.log("App", divRef);
  return <Component reRender={reRender} passPropsToDiv={{ ref: divRef }} />;
}

const Component = ({ passPropsToDiv, reRender }) => {
  const div1Ref = useRef();
  const { ref: extraRef = null, ...passPropsToDivNoRef } = passPropsToDiv ?? {};
  extraRef.current = div1Ref.current;
  console.log("Component", div1Ref);

  return (
    <div className="App">
      <div ref={div1Ref} {...passPropsToDivNoRef}>
        i will have a ref
      </div>
      <button onClick={reRender}>reRender</button>
    </div>
  );
};

codesandbox: https://codesandbox.io/s/react-use-pass-multiple-refs-legm7p?file=/src/App.js

언급URL : https://stackoverflow.com/questions/53561913/react-forwarding-multiple-refs

반응형