React memo function with isEqual - reactjs

I have this React.memo component that I want to render only if the props doesn't change with sending a second argument isEqual function.
When I console.log the wrapper component and the memmoized component I can see that its being rendered with the same props.. What am I doing wrong?
My wrapper component
export const WrapperComponent= props => {
console.log('MemoizeComponent', props);
return (
<MemoizeComponent name="memo"/>
);
}
export const WrapperComponent;
My memmoized component
export const Component = props => {
console.log('component: ', props.name)
return (
<div>{props.name}</div>
);
}
function isEqual(prevProps, nextProps) {
console.log(prevProps.name);
console.log(nextProps.name);
return prevProps.name === nextProps.name;
};
export const MemoizeComponent = React.memo(Component, isEqual);
console output:
memo
memo
component:memo
memo
memo
component:memo

Not sure what your question is but your code as is works correctly:
const { useState, memo, useRef } = React;
const useRendered = () => {
const rendered = useRef(0);
rendered.current++;
return rendered.current;
};
function App() {
const [, setRender] = useState();
const rendered = useRendered();
return (
<div>
<div>rendered {rendered} times</div>
<button onClick={() => setRender({})}>
re render
</button>
<WrapperComponent name="memo" />
</div>
);
}
const WrapperComponent = props => {
return <MemoizeComponent name="memo" />;
};
const Component = props => {
const rendered = useRendered();
return (
<div>
{props.name} rendered {rendered} times
</div>
);
};
function isEqual(prevProps, nextProps) {
return prevProps.name === nextProps.name;
}
const MemoizeComponent = memo(Component, isEqual);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related

Call function from React component in other component

Can you help me?
I have two functional components and I need to use function from first component in second component.
I want to use function "sayHello" in function onClicked, but I don't know how to do it.
import React from 'react';
type Props = {
}
const Component_1: React.FunctionComponent<Props> = () => {
const sayHello = () => {
console.log('----Hello');
}
return (
<div className="">
Component 1
</div>
);
};
export default React.memo(Component_1);
const Component_2: React.FunctionComponent<Props> = () => {
const onClicked = () => {
//How ???
//Component_1.sayHello()
}
return (
<div className="">
<div onClick={onClicked}>
Click me
</div>
<Component_1/>
</div>
);
};
const Component_1 = (props) => {
const sayHello = () => {
console.log("----Hello");
};
props.onClicked(sayHello);
return <div className="">Component 1</div>;
};
const Component_2 = () => {
let sayHello;
const fn = function (sayHelloFromComp1) {
sayHello = sayHelloFromComp1;
};
const onClicked = (e) => {
//How ???
//Component_1.sayHello()
sayHello();
};
return (
<div className="">
<div onClick={onClicked}>Click me</div>
<Component_1 onClicked={fn} />
</div>
);
};
export default Component_2;

How do you pass props to functional components which are to be used using dot notation?

I have following code:
import React, { useState } from 'react'
const Dropdown = ({children}) => {
const [showMenu, setShowMenu] = useState(false)
const handleShow = () => setShowMenu(!showMenu)
return <div>{children}</div>
}
const Button = ({children, showMenu}) => {
return <div onClick={() => showMenu()}>{children}</div>
}
const Menu = ({children}) => <ul>{children}</ul>
const Item = ({children}) => <li>{children}</li>
Dropdown.Button = Button
Dropdown.Menu = Menu
Dropdown.Item = Item
export default Dropdown
I want to pass showMenu from Dropdown function such that it can be accessed by Button component and Menu component
How can I achieve that using functional components
As mentioned in the comments, the most commonly used options are:
1. React Context
const { useState, useContext, createContext } = window.React;
const DropdownContext = createContext({
showMenu: false,
setShowMenu: () => true,
});
const Dropdown = ({children}) => {
const [showMenu, setShowMenu] = useState(false)
return (
<DropdownContext.Provider value={{ showMenu, setShowMenu }}>
<div>{children}</div>
</DropdownContext.Provider>
);
}
const Button = ({children}) => {
const { showMenu, setShowMenu } = useContext(DropdownContext);
return <div onClick={() => setShowMenu(!showMenu)}>{children} {showMenu ? 'show' : 'hide'}</div>
}
const Menu = ({children}) => <ul>{children}</ul>
const Item = ({children}) => <li>{children}</li>
Dropdown.Button = Button
Dropdown.Menu = Menu
Dropdown.Item = Item
function App() {
return (
<div>
<Dropdown>
<Dropdown.Button>Button</Dropdown.Button>
</Dropdown>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
2. Controlled Component
const { useState } = window.React;
const Dropdown = ({children}) => {
return (
<div>{children}</div>
);
}
const Button = ({children, onClick, showMenu}) => {
return <div onClick={onClick}>{children} {showMenu ? 'show' : 'hide'}</div>
}
const Menu = ({children}) => <ul>{children}</ul>
const Item = ({children}) => <li>{children}</li>
Dropdown.Button = Button
Dropdown.Menu = Menu
Dropdown.Item = Item
function App() {
// with controlled components, the state is managed in a parent component or (global) state
const [showMenu, setShowMenu] = useState(false)
return (
<div>
<Dropdown showMenu={showMenu}>
<Dropdown.Button
showMenu={showMenu}
onClick={() => setShowMenu(!showMenu)}
>
Button
</Dropdown.Button>
</Dropdown>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>

In which order are React components re-rendered when global state is updated through hooks?

Given a top-level App component that renders the following heirarchy:
<Parent>
<Child />
</Parent>
If both Parent and Child call the same hook to obtain some global state, and that state changes, will Parent or Child be re-rendered first?
Also, say they both use some variable, user, from global state, and that Parent only renders its children prop if user is not undefined. Will the Child prop ever be rendered with an undefined user?
Here is a snippet logging mount/unmount of parent and child. Child is only rendered when the state value is odd. Both components are accessing the same Context.
const { useState, createContext, useContext, useEffect, useRef } = React;
const ViewContext = createContext();
const ActionsContext = createContext();
function MyContainer() {
const [contextState, setContextState] = useState(0);
return (
<ViewContext.Provider value={contextState}>
<ActionsContext.Provider value={setContextState}>
<Incrementor />
<Parent />
</ActionsContext.Provider>
</ViewContext.Provider>
)
}
function Incrementor() {
const setContextState = useContext(ActionsContext);
const increment = () => {
console.clear();
setContextState(p => p + 1);
}
return <button onClick={increment}>increment</button>;
}
function Parent() {
const contextState = useContext(ViewContext);
useEffect(() => {
console.log(contextState, ' - Parent Mounted');
return () => console.log(contextState, ' - Parent Unmounted');
}, [contextState]);
return (
<div>
<p>This is the parent: {contextState}</p>
{contextState % 2
? <ConditionalChild />
: null}
</div>
);
}
function ConditionalChild() {
const contextState = useContext(ViewContext);
useEffect(() => {
console.log(contextState, ' - Child Mounted');
return () => console.log(contextState, ' - Child Unmounted');
}, [contextState]);
return (
<div>
<p>This is the child: {contextState}</p>
</div>
);
}
ReactDOM.render(
<MyContainer />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

How to return a component and a function, or what's the alternative?

[React] What is the "way" to send/share a function between components?
Better explained in (useless) code
Here I have no problem since everything is in the same component (https://codesandbox.io/s/compassionate-ishizaka-uzlik)
import React, { useState } from "react";
export default function App() {
const [bookmarks, setBookmarks] = useState();
const letbook = () => setBookmarks("hello");
const Card = () => <div onClick={letbook}>hey</div>;
const MyCom = () => {
return <div><Card /></div>;
};
return (
<div className="App">
<h1 onClick={letbook}>Hello CodeSandbox</h1>
<MyCom />
<div>{bookmarks}</div>
</div>
);
}
But then, if now I want to split code, how do I do this? The problem is how to share letbook (this code doesn't work)
import React, { useState } from "react";
export default function App() {
const Card = () => <div onClick={letbook}>hey</div>;
return (
<div className="App">
<h1 onClick={letbook}>Hello CodeSandbox</h1>
<MyCom />
<div>{bookmarks}</div>
</div>
);
}
const MyCom = () => {
const [bookmarks, setBookmarks] = useState();
const letbook = () => setBookmarks("hello");
return (
<div>
<Card />
</div>
);
};
I could use a hook that returned the component and the function
const [letbook, MyCom] = useMyCom
But this is not recommended (https://www.reddit.com/r/reactjs/comments/9yq1l8/how_do_you_feel_about_a_hook_returning_components/)
Then I can use a hook and a component, as with the following code, but the code itself seems obfuscated to me, to a point that I doubt whether I should split the code or not
Unless (and this is the question) whether there is a smarter way to do this
import React, { useState } from "react";
export default function App() {
const [bookmarks, setBookmarks, letbook] = useMyCom();
return (
<div className="App">
<h1 onClick={letbook}>Hello CodeSandbox</h1>
<MyCom card={props => <Card letbook={letbook} />} />
<div>{bookmarks}</div>
</div>
);
}
const Card = ({letbook}) => <div onClick={letbook}>hey</div>;
const useMyCom = () => {
const [bookmarks, setBookmarks] = useState();
const letbook = () => setBookmarks("hello");
return [bookmarks, setBookmarks, letbook];
};
const MyCom = ({ letbook, card }) => <div>{card(letbook)}</div>;
Split your component to reuse it is definitely a good idea. But make sure your are using and manipulate a single state in the same file an pass it as props. Also, it is important that you avoid to re-render your child component. Only when your main component change props that are necessary to re-render your child component.
import React, { useState, memo } from "react";
const MyCom = memo(props => {
return <div>{props.bookmarks}</div>;
});
export default function App() {
const [bookmarks, setBookmarks] = useState();
const letbook = () => setBookmarks("hello");
return (
<div className="App">
<h1 onClick={letbook}>Hello CodeSandbox</h1>
<MyCom bookmarks={bookmarks} />
</div>
);
}

How to implement HOC characteristics width useHooks?

I'm want to rewrite my high-order-component with useHooks. it is possible reuse stateful logic like hoc?
I have worked with hoc for a while, I think it is esay to solution some problem.
I tried to implement same features like hoc use useHooks, sorry... I failed
// HOC
const Hoc = WrapperComponent => (
class extends React.Component {
state = {
toggle: false
}
handleClick = () => {
this.setState({ toggle: !this.state.toggle })
}
render() {
const { toggle } = this.state
return (
<>
<button onClick={handleClick}>click</button>
{toggle && <WrapperComponent />}
</>
)
}
}
)
// Component A
function CompA () {
return 'class comp a'
}
// reuse logic with hoc
export default Hoc(CompA)
// this is my code.
// but i think it's hoc style. not really hooks idea
function useHooks(WrapperComponent) {
const [toggle, setToggle] = useState(false)
return () => (
<>
<button onClick={() => setToggle(!toggle)}>click</button>
{toggle && <WrapperComponent />}
</>
)
}
//
export default useHooks(ClassCompA)
Hooks is designed to share any necessary logic between the components.
Presentational elements like JSX are not included in this logic. They are best left at the components which can be composed to any level necessary.
For your example using the HOC, there would need to be a component for the presentation and hooks for sharing the logic.
const { useState, Fragment } = React;
function useToggle() {
const [ show, setShow ] = useState(false);
const toggle = () => {
setShow(show => !show);
}
return {
show,
toggle,
}
}
function Toggler({ children }) {
const { show, toggle } = useToggle();
return (
<Fragment>
{show && children }
{<button onClick={toggle}>Toggle View</button>}
</Fragment>
);
}
function App() {
return (
<Toggler>
<h1>This content can be toggled</h1>
</Toggler>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>

Resources