PropTable should render only if receives props from other component
const PropTable = (props) => {
const { availableProp } = props;
...
return(...)
}
This'd get your job done
const PropTable = (props) => {
const { availableProp } = props;
...
return availableProp ? (...) : null
}
Related
Can we pass hook as a function to a component and use it in that component?
Like in the example below I am passing useProps to withPropConnector which returns a Connect component. This useProps is being used in the Connect component. Am I violating any hook rules?
// Landing.jsx
export const Landing = (props) => {
const { isTypeOne, hasFetchedData } = props;
if (!hasFetchedData) {
return <Loader />;
}
const renderView = () => {
if (isSomeTypeOne) {
return <TypeOneView />;
}
return <TypeTwoView />;
};
return (
<>
<Wrapper>
{renderView()}
<SomeNavigation />
</Wrapper>
<SomeModals />
</>
);
};
const useProps = () => {
const { query } = useRouter();
const { UID } = query;
const { isTypeOne, isTypeTwo } = useSelectorWithShallowEqual(getType);
const hasFetchedData = useSelectorWithShallowEqual(
getHasFetchedData(UID)
);
const props = {
isTypeOne,
isTypeTwo,
hasFetchedData
};
return props;
};
export default withPropConnector(useProps, Landing);
// withPropConnector.js
const withPropConnector = (useProps, Component) => {
const Connect = (propsFromParent = emptyObject) => {
const props = useProps(propsFromParent);
return <Component {...propsFromParent} {...props} />;
};
return Connect;
};
export default withPropConnector;
I am trying to call a function from a different component but when I console.log('hi') it appear but it didn't call the messageContext.
Here is my follwing code from Invitees.js:
const [showPreview, setShowPreview] = useState(false);
const toggleUserPreview = () => {
setShowPreview(!showPreview);
};
{showPreview && (
<ResultsWrappers togglePreview={toggleUserPreview}>
<UserPreview
userInfo={applicant}
skillStr={applicant.Skills}
togglePreview={toggleUserPreview}
/>
</ResultsWrappers>
)}
Here is the component have the function I want to call UserPreview.js:
import { useMessageContextProvider } from "../context/MessageContext";
const UserPreview = ({ userInfo, skillStr, togglePreview }) => {
const messageContextProvider = useMessageContextProvider();
const messageUser = () => {
togglePreview();
messageContextProvider.updateActiveUserToMessage(userInfo);
console.log('hi');
};
...
};
Here is my messageContext:
import { createContext, useContext, useState } from "react";
const messageContext = createContext();
export const MessageContextProvider = ({ children }) => {
const [activeUserToMessage, setActiveUserToMessage] = useState({});
const [isOpenMobileChat, toggleMobileChat] = useState(false);
const updateActiveUserToMessage = (user) => {
setActiveUserToMessage(user);
};
return (
<messageContext.Provider
value={{
updateActiveUserToMessage,
activeUserToMessage,
isOpenMobileChat,
toggleMobileChat,
}}
>
{children}
</messageContext.Provider>
);
};
export const useMessageContextProvider = () => {
return useContext(messageContext);
};
When the messageContext called it should open the chatbox like this:
The code you showing is not enough to say it for 100%, but it seems like toggleUserPreview - function called twice, so it reverted to original boolean value.
One time as <ResultsWrappers togglePreview={toggleUserPreview}/>
and second time as <UserPreview togglePreview={toggleUserPreview}/>.
import {
Consumer,
IFormConsumer
} from "react-context-form/src";
import React, { FunctionComponent, useState } from "react";
import Table from './table';
import {Modal} from './modal'
interface ListProps{
// list props
}
interface TargetProps{
// target props
}
interface ValueProps {
// value props
}
interface ReturnProps {
// return props
}
export const List: FunctionComponent<ListProps> = ({
readOnly = false
}) => {
const [formModalOpen, setFormModalOpen] = useState<boolean>(false);
const onFormCancel = () => {
setFormModalOpen(false)
};
const [targetRow, setTargetRow] = useState<TargetProps | undefined>(
undefined
);
const onCreateClick = () => {
setTargetRow(undefined);
setFormModalOpen(true);
};
const handleEdit = (row: any) => {
setTargetRow(row.original);
setFormModalOpen(true);
}
let arr: any = []; // some data
let newArr: any = []; // some data
const fieldOptions = () => {
return [...arr, ...newArr];
};
const getInitialData = (
values: ValueProps
): ReturnProps[] => {
const data = get(values, "gqlMedia");
return data && Array.isArray(data) ? data.slice() : [];
};
return (
<Consumer>
{(consumerProps: IFormConsumer) => {
const initialData = getInitialData(consumerProps.values);
return (
<>
<Modal
isOpen={formModalOpen}
onCancel={onFormCancel}
targetRow={targetRow}
data={initialData}
fieldOptions={fieldOptions}
/>
<Table
initialData={initialData}
handleEdit={handleEdit}
onCreateClick={onCreateClick}
readOnly
fieldOptions={fieldOptions}
/>
<>
)
}}
</Consumer>
);
};
When I move to a page other than the 1st page in the table and edit a row, the edit modal opens. The table is automatically rendering the 1st page in the background. The page should stay when the modal is opened. I don't want the Table component to be rerendered when the modal is opened (the state is changed). Tried using useCallback, useMemo, React.memo. Not able to find a solution.
I would like to rewrite this life cycle method into a hook but it does'nt work as expected.
when the componentdidmounted, if the user id exists in the local storage,the user is connected and his name is displayed in the navbar. And when he disconnects and reconnects his name is displayed in the navbar.
So i am trying to convert this class Component with hooks, when the username changes nothing is displayed in the navbar so i have to refresh the page and that way his name is displayed
The real problem is the componentDidUpdate
how can i get and compare the prevProps with hooks
The class Component
const mapStateToProps = state => ({
...state.authReducer
}
);
const mapDispatchToProps = {
userSetId,
userProfilFetch,
userLogout
};
class App extends React.Component {
componentDidMount() {
const userId = window.localStorage.getItem("userId");
const {userSetId} = this.props;
if (userId) {
userSetId(userId)
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
const {userId, userProfilFetch, userData} = this.props; //from redux store
if(prevProps.userId !== userId && userId !== null && userData === null){
userProfilFetch(userId);
}
}
render() {
return (
<div>
<Router>
<Routes/>
</Router>
</div>
);
}
}
export default connect(mapStateToProps,mapDispatchToProps)(App);
With hooks
const App = (props) => {
const dispatch = useDispatch();
const userData = useSelector(state => state.authReducer[props.userData]);
const userId = window.localStorage.getItem("userId");
useEffect(()=> {
if(!userId){
dispatch(userSetId(userId))
dispatch(userProfilFetch(userId))
}
}, [userData, userId, dispatch])
return(
<Router>
<Routes/>
</Router>
)
};
export default App;
How to get the previous props or state?
Basically create a custom hook to cache a value:
const usePrevious = value => {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Usage:
const App = (props) => {
const dispatch = useDispatch();
const userData = useSelector(state => state.authReducer[props.userData]);
const userId = window.localStorage.getItem("userId");
// get previous id and cache current id
const prevUserId = usePrevious(userId);
useEffect(()=> {
if(!userId){
dispatch(userSetId(userId))
dispatch(userProfileFetch(userId))
}
// do comparison with previous and current id value
if (prevUserId !== userId) {
dispatch(userProfileFetch(userId));
}
}, [userData, userId, prevUserId, dispatch])
return(
<Router>
<Routes/>
</Router>
)
};
FYI: You may want to refactor the code a bit to do the fetch from local storage in an effect hook that runs only on mount. If I understand your app flow correctly it would look something like this:
const App = (props) => {
const dispatch = useDispatch();
const { userId } = useSelector(state => state.authReducer[props.userData]);
useEffect(() => {
const userId = window.localStorage.getItem("userId");
userId && dispatch(userSetId(userId));
}, []);
// get previous id and cache current id
const prevUserId = usePrevious(userId);
useEffect(()=> {
if(!userId){
dispatch(userSetId(userId))
dispatch(userProfileFetch(userId))
}
// do comparison with previous and current id value
if (prevUserId !== userId) {
dispatch(userProfileFetch(userId));
}
}, [userId, prevUserId, dispatch])
return(
<Router>
<Routes/>
</Router>
)
};
now i resolve it, i made this
const App = props => {
const userId = window.localStorage.getItem("userId");
const dispatch = useDispatch();
const userData = useSelector(state=> state.authReducer[props.userData]);
const isAuthenticated = useSelector(state=> state.authReducer.isAuthenticated);
useEffect(()=> {
if(userId){
dispatch(userSetId(userId))
dispatch(userProfilFetch(userId))
}
}, [userId])
return(
<div>
<Router>
<Routes/>
</Router>
</div>
)
};
Just as the title says, I don't understand in this code what does the subscribers.
import React from "react";
const stateFromStore = sessionStorage.getItem('user');
let state = stateFromStore ? JSON.parse(stateFromStore) : null;
const subscribers = [];
const unsubscribe = subscriber => {
const index = subscribers.findIndex(subscriber);
index >= 0 && subscribers.splice(index, 1);
};
const subscribe = subscriber => {
subscribers.push(subscriber);
return () => unsubscribe(subscriber);
};
export const withUser = Component => {
return class WithUser extends React.Component {
componentDidMount() {
this.unsubscribe = subscribe(this.forceUpdate.bind(this));
}
render() {
const newProps = { ...this.props, user: state };
return <Component {...newProps} />;
}
componentWillUnmount() {
this.unsubscribe();
}
};
};
export const update = newState => {
state = newState;
sessionStorage.setItem('user', state ? JSON.stringify(state) : null);
subscribers.forEach(subscriber => subscriber());
};
I get the part about sessionStorate but I don't understand the use of the subscribers array.
This is part of an example about how to use passport with react https://github.com/HackedByChinese/passport-examples/tree/master/example-simple-react/client/src