Chức năng trong các thành phần không trạng thái?


90

Tôi đang cố chuyển đổi <canvas>hoạt ảnh thú vị mà tôi tìm thấy ở đây thành một thành phần có thể tái sử dụng React. Có vẻ như thành phần này sẽ yêu cầu một thành phần mẹ cho canvas và nhiều thành phần con cho function Ball().

Vì lý do hiệu suất, có lẽ sẽ tốt hơn nếu tạo Ballsthành các thành phần không trạng thái vì sẽ có nhiều thành phần trong số đó. Tôi không quen với việc tạo các thành phần không trạng thái và đang tự hỏi tôi nên xác định vị trí this.update()và các this.drawchức năng được định nghĩa trong function Ball().

Các chức năng cho các thành phần không trạng thái đi vào bên trong thành phần hay bên ngoài? Nói cách khác, cái nào sau đây tốt hơn?

1:

const Ball = (props) => {
    const update = () => {
        ...
    }

    const draw = () => {
        ...
    }

    return (
       ...
    );
}

2:

function update() {
     ...
}

function draw() {
     ...
}

const Ball = (props) => {
    return (
       ...
    );
}

Ưu / nhược điểm của mỗi loại là gì và chúng có tốt hơn cho các trường hợp sử dụng cụ thể như của tôi không?


Bạn có thể đăng mã hiện có để chúng tôi xem nó sẽ được sử dụng như thế nào không?
Scimonster

@Scimonster Tôi đã đăng nó trong một liên kết nhúng, có thể bạn đã bỏ qua nó. Đây là liên kết: codepen.io/awendland/pen/XJExGv
MarksCode

Câu trả lời:


113

Điều đầu tiên cần lưu ý là các thành phần chức năng không trạng thái không thể có các phương thức, bạn không nên tin tưởng vào việc gọi updatehoặc drawtrên một kết xuất Ballnếu nó là một thành phần chức năng không trạng thái.

Trong hầu hết các trường hợp, bạn nên khai báo các hàm bên ngoài hàm thành phần, do đó bạn chỉ khai báo chúng một lần và luôn sử dụng lại cùng một tham chiếu. Khi bạn khai báo hàm bên trong, mỗi khi thành phần được hiển thị, hàm sẽ được định nghĩa lại.

Có những trường hợp mà bạn sẽ cần phải xác định một hàm bên trong thành phần, chẳng hạn như gán nó như một trình xử lý sự kiện hoạt động khác nhau dựa trên các thuộc tính của thành phần. Nhưng bạn vẫn có thể xác định hàm bên ngoài Ballvà liên kết nó với các thuộc tính, làm cho mã sạch hơn nhiều và làm cho updatehoặc các drawhàm có thể sử dụng lại.

// You can use update somewhere else
const update (propX, a, b) => { ... };

const Ball = props => (
  <Something onClick={update.bind(null, props.x)} />
);

Nếu bạn đang sử dụng hook , bạn có thể sử dụng useCallbackđể đảm bảo hàm chỉ được xác định lại khi một trong các phần phụ thuộc của nó ( props.xtrong trường hợp này) thay đổi:

const Ball = props => {
  const onClick = useCallback((a, b) => {
    // do something with a, b and props.x
  }, [props.x]);

  return (
    <Something onClick={onClick} />
  );
}

Đây là cách sai :

const Ball = props => {
  function update(a, b) {
    // props.x is visible here
  }

  return (
    <Something onClick={update} />
  );
}

Khi sử dụng useCallback, việc xác định updatechức năng trong useCallbackhook, bên ngoài thành phần của chúng ta trở thành một quyết định thiết kế hơn bất kỳ điều gì, bạn nên tính đến việc bạn có định sử dụng lại updatehay không và / hoặc nếu bạn cần truy cập phạm vi đóng của thành phần, ví dụ, đọc / ghi vào trạng thái. Cá nhân tôi chọn xác định nó bên trong thành phần theo mặc định và chỉ làm cho nó có thể sử dụng lại nếu có nhu cầu, để ngăn chặn kỹ thuật quá mức ngay từ đầu. Trên hết, việc sử dụng lại logic ứng dụng được thực hiện tốt hơn với các hook cụ thể hơn, để lại các thành phần cho các mục đích trình bày. Việc xác định hàm bên ngoài thành phần trong khi sử dụng hook thực sự phụ thuộc vào cấp độ tách khỏi React mà bạn muốn cho logic ứng dụng của mình.


Cảm ơn Marco, điều đó làm rõ ràng mọi thứ một chút. Điều tôi bối rối trong trường hợp của mình là liên quan đến this.drawchức năng bên trong Ball. Nó sử dụng ctxtừ những gì sẽ là của cha mẹ <canvas>và cũng sử dụng thistừ khóa cho những gì sẽ là Ballthành phần con . Cách tốt nhất để tích hợp triển khai thành phần không trạng thái để cả hai thuộc tính đó đều có thể truy cập được?
MarksCode

không có thiskhi sử dụng các thành phần chức năng không trạng thái, hãy ghi nhớ điều đó. Đối với bối cảnh canvas, bạn sẽ phải chuyển nó đến từng cái một Ball, điều đó nghe có vẻ không tốt chút nào.
Marco Scabbiolo

Vì vậy, trong trường hợp này tốt nhất là không có thành phần con nào bạn đang nói?
MarksCode

1
@MarcoScabbiolo không không, đó không phải là trường hợp của tôi, đã sử dụng các chức năng mũi tên tự nhiên trong một thời gian khá dài, vì trình duyệt duy nhất không hỗ trợ chúng là IE. Trên thực tế, tôi đã tìm thấy nhận xét này từ một bài báo , nơi nó thực sự tuyên bố rằng bindcụ thể trong Chrome trước 59 thậm chí còn chậm hơn các chức năng mũi tên. Và trong Firefox, nó cũng khá lâu vì cả hai đều hoạt động với cùng tốc độ. Vì vậy, tôi muốn nói trong trường hợp này không có khác biệt gì là cách ưa thích :)
Vadim Kalinin

1
@ MauricioAvendaño dù theo cách nào cũng hoạt động, nhưng việc Somethingthành phần biết rằng có một prop X trong thành phần mẹ của nó là một cách thực hiện không tốt . Điều tương tự cũng xảy ra cho câu hỏi bạn đang hỏi và mã mẫu mà tôi đã viết, nó phụ thuộc vào ngữ cảnh, được bỏ qua vì mục đích đơn giản.
Marco Scabbiolo

13

Chúng ta có thể có các chức năng bên trong các thành phần chức năng không trạng thái, dưới đây là ví dụ:

 const Action = () => {
  function  handlePick(){
     alert("test");
  }
  return (
    <div>
      <input type="button" onClick={handlePick} value="What you want to do ?" />
    </div>
  );
}

Tuy nhiên, đây không phải là một phương pháp hay vì hàm handlePick()sẽ được xác định mỗi khi thành phần được gọi.


11
Nếu nó không phải là một thực hành tốt, thì giải pháp thay thế sẽ là gì?
John Samuel,

@JohnSamuel Cách thay thế là xác định handlePick()bên trên / bên ngoài thành phần giống như function handlePick() { ... }; const Action = () => { ... }kết quả là handlePick chỉ được xác định một lần. Nếu bạn cần dữ liệu từ Actionthành phần, bạn nên chuyển nó dưới dạng tham số cho handlePickhàm.
James Hay

12
nếu đây không phải là một thực hành tốt, bạn có thể đã thêm thực hành tốt với câu trả lời? bây giờ tôi phải tìm kiếm một lần nữa cho việc thực hành tốt :(
Shamseer Ahammed

2

Chúng ta có thể sử dụng React hook useCallbacknhư bên dưới trong một thành phần chức năng:

const home = (props) => {
    const { small, img } = props
    const [currentInd, setCurrentInd] = useState(0);
    const imgArrayLength = img.length - 1;
    useEffect(() => {
        let id = setInterval(() => {
            if (currentInd < imgArrayLength) {
                setCurrentInd(currentInd => currentInd + 1)
            }
            else {
                setCurrentInd(0)
            }
        }, 5000);
        return () => clearInterval(id);
    }, [currentInd]);
    const onLeftClickHandler = useCallback(
        () => {
            if (currentInd === 0) {

            }
            else {
                setCurrentInd(currentInd => currentInd - 1)
            }
        },
        [currentInd],
    );

    const onRightClickHandler = useCallback(
        () => {
            if (currentInd < imgArrayLength) {
                setCurrentInd(currentInd => currentInd + 1)
            }
            else {

            }
        },
        [currentInd],
    );
    return (
        <Wrapper img={img[currentInd]}>
            <LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}>
                <img src={Icon_dir + "chevron_left_light.png"}></img>
            </LeftSliderArrow>
            <RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}>
                <img src={Icon_dir + "chevron_right_light.png"}></img>
            </RightSliderArrow>
        </Wrapper>);
}

export default home;

Tôi nhận được 'img' từ nó là cha mẹ và đó là một mảng.


0

Nếu bạn muốn sử dụng đạo cụ hoặc trạng thái của thành phần trong chức năng, điều đó phải được xác định trong thành phần với useCallback.

function Component(props){
  const onClick=useCallback(()=>{
     // Do some things with props or state
  },[])
}

Mặt khác, nếu bạn không muốn sử dụng đạo cụ hoặc trạng thái trong chức năng, hãy xác định điều đó bên ngoài thành phần.

const computeSomethings=()=>{
   // Do some things with params or side effects
}

function Component(props){
  
}

3
bạn có thể cho một ví dụ về việc sử dụng hook for method bên trong function? (phương pháp nhà nước không được thiết lập)
jake-ferguson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.