getContext and withContext not working - reactjs

I've been trying to pass id to other component with context, but I get undefined, somewhere i'm making an error.
As I understand we should get context as props.
Any Ideas ?
import {compose,withContext} from 'recompose'
const ComponentOne = ({id}) => {
console.log(id) // cizlory7iji600149711su9vj
...
}
const Context = withContext(
{id:React.PropTypes.string},
(props) => ({id:props.id})
)
export default compose(Context)(ComponentOne)
SecondComponent.js
import {compose,getContext} from 'recompose'
const ComponentTwo = ({id}) => {
console.log(id) // undefined
...
}
const GetContext = getContext(
{id:React.PropTypes.string}
)
export default compose(GetContext)(ComponentTwo)

Context only works from parents to children by passing props down, not siblings.
Make ComponentTwo a child of ComponentOne.

Related

React Context update value from provider wrapping child

This may be a simple problem with React Context, but I cant find a way to do what I need.
I have a component, which consumes some context:
export const App = () => {
const value = useContext(MyContext);
return <ComponentA>{value}</ComponentA>;
};
The context is in a different module:
import { createContext } from 'react';
export const MyContext = createContext("Default value");
Now, ComponentA has a child component, which wraps the children from ComponentA:
const ComponentB = ({ children }) => {
return <div>{children}</div>;
};
export const ComponentA: React.FC = ({ children }) => {
return (
<MyContext.Provider value='Modified value'>
<ComponentB>{children}</ComponentB>
</MyContext.Provider>
);
};
I expect the text to be updated, and App to render "Updated value"; but instead it renders "Default value".
Does anyone know why this happen? Here are two sandboxes, the first with the example above—https://codesandbox.io/s/dnd-kit-sortable-forked-cm2vnv— and the second trying to update the context with useState: https://codesandbox.io/s/dnd-kit-sortable-forked-e6vrhp
Move the consumption of you context below the context provider.
In your example it should be in ComponentB
export const ComponentB = ({ children }) => {
const value = useContext(MyContext);
return (
<>
{value} — (should render «Updated value»)
{children}
</>
);
};

Redux cant access state after added

i have a parent component and one child component (custom function component). in my child component i have event handler that will change the state (redux) from the parent. everything work fine when i call the addProduct function the state is added i can see in my redux tools product state is changed. But Why after i added i cant access that state (console.log (product._id)) i get a error message a product is null and one thing make me confused is i can access that state in my JSX from parent Component ({JSON.stringify(product)}) but not after i added.
here is my code
import React, { Fragment } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import {addProduct} from '../action/product';
const ChildComponent = ({onClick}) => {
return (
<button onClick={onClick}>Add</button>
)
}
const ParentComponent = ({product}) => {
const onNotFoundThenAddNew = () => {
addProduct ({name : 'new product'});
console.log(product._id);
}
return (
<Fragment>
{JSON.stringify(product)}
<ChildComponent onClick={onNotFoundThenAddNew}/>
</Fragment>
)
}
ParentComponent.propTypes = {
addProduct : PropTypes.func,
product : PropTypes.object
};
const mapStateToProps = (state) => ({
product : state.product.product
})
export default connect (mapStateToProps, {addProduct}) (ParentComponent)

React: A service returning a ui component (like toast)?

Requirement: Show toast on bottom-right corner of the screen on success/error/warning/info.
I can create a toast component and place it on any component where I want to show toasts, but this requires me to put Toast component on every component where I intend to show toasts. Alternatively I can place it on the root component and somehow manage show/hide (maintain state).
What I am wondering is having something similar to following
export class NotificationService {
public notify = ({message, notificationType, timeout=5, autoClose=true, icon=''}: Notification) => {
let show: boolean = true;
let onClose = () => {//do something};
if(autoClose) {
//set timeout
}
return show ? <Toast {...{message, notificationType, onClose, icon}} /> : </>;
}
}
And call this service where ever I need to show toasts.
Would this be the correct way to achieve the required functionality?
You can use AppContext to manage the state of your toast and a hook to trigger it whenever you want.
ToastContext:
import React, { createContext, useContext, useState } from 'react';
export const ToastContext = createContext();
export const useToastState = () => {
return useContext(ToastContext);
};
export default ({ children }) => {
const [toastState, setToastState] = useState(false);
const toastContext = { toastState, setToastState };
return <ToastContext.Provider value={toastContext}>{children}</ToastContext.Provider>;
};
App:
<ToastProvider>
<App/>
<Toast show={toastState}/>
</ToastProvider>
Then anywhere within your app you can do:
import {useToastState} from 'toastContext'
const {toastState, setToastState} = useToastState();
setToastState(!toastState);

Trying to use a function that is in my context provider file

I am using Context-Api and am trying to use a function provided from my file in a lifecycle method. the function isnt wrapped in a consumer of course so i looked at the documentation and set value to context. this still isnt working.Everyting is working in my return of my class component but component did mount does not work.
import { ProductConsumer } from '../context';
export default class Details1 extends Component
componentDidMount() {
let value = this.context;
let id = this.props.match.params.id;
value.handleDetail(id);
}
render() {
{value => {
const {
id,...} = value.detailProduct;
return (
<ProductConsumer>
{value => {
My Component
</ProductConsumer>
export const Details = () => (
<Product.Consumer>
{context =>
<Details1 context={context}/>
}
</Product.Consumer>
)
You can either wrap the component with the consumer, passing it the function as a prop, or (better - ) convert your component to a functional component, using the useContext hook to get the values from your context.
import React, { useContext } from "react";
import someContext from "./context-path";
const MyComponent = () => {
const { myFunction } = useContext(someContext);
...
};

React / Redux wait for store to update

I have a problem that a react component is rendering before the redux store has any data.
The problem is caused by the React component being rendered to the page before the existing angular app has dispatched the data to the store.
I cannot alter the order of the rendering or anything like that.
My simple React component is
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {addBot} from './actions';
class FlowsContainer extends React.Component {
componentDidMount() {
this.props.initStoreWithBot();
}
render() {
// *** at this point I have the store in state prop
//but editorFlow array is not yet instanced, it's undefined
const tasks = this.props.state.editorFlow[0].flow.tasks
return (
<div>
Flow editor react component in main container
</div>
);
}
}
const mapStateToProps = (state) => ({
state : state
})
const mapDispatchToProps = (dispatch) => {
return {
initStoreWithBot : () => dispatch(addBot("test 123"))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(FlowsContainer)
So how can I hold off the rendering until editorFlow array has elements ?
You can use Conditional Rendering.
import {addBot} from './actions';
class FlowsContainer extends React.Component {
componentDidMount() {
this.props.initStoreWithBot();
}
render() {
// *** at this point I have the store in state prop
//but editorFlow array is not yet instanced, it's undefined
const { editorFlow } = this.props.state;
let tasks;
if (typeof editorFlow === 'object' && editorFlow.length > 0) {
tasks = editorFlow[0].flow.tasks;
}
return (
{tasks &&
<div>
Flow editor react component in main container
</div>
}
);
}
}
const mapStateToProps = (state) => ({
state : state
})
const mapDispatchToProps = (dispatch) => {
return {
initStoreWithBot : () => dispatch(addBot("test 123"))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(FlowsContainer)
As far as I know, you can't.
the way redux works is that it first renders everything, then actions take place with some async stuff(such as loading data), then the store gets populated, and then redux updates the components with the new state(using mapStateToProps).
the lifecycle as I understand it is this :
render the component with the initial state tree that's provided when you create the store.
Do async actions, load data, extend/modify the redux state
Redux updates your components with the new state.
I don't think mapping the entire redux state to a single prop is a good idea, the component should really take what it needs from the global state.
Adding some sane defaults to your component can ensure that a "loading" spinner is displayed until the data is fetched.
In response to Cssko (I've upped your answer) (and thedude) thanks guys a working solution is
import React, {Component} from 'react';
import { connect } from 'react-redux';
import {addBot} from './actions';
class FlowsContainer extends React.Component {
componentDidMount() {
this.props.initStoreWithBot();
}
render() {
const { editorFlow } = this.props.state;
let tasks;
if (typeof editorFlow === 'object' && editorFlow.length > 0) {
tasks = editorFlow[0].flow.tasks;
}
if(tasks){
return (
<div>
Flow editor react component in main container
</div>
)
}
else{
return null;
}
}
}
const mapStateToProps = (state) => ({
state : state
})
const mapDispatchToProps = (dispatch) => {
return {
initStoreWithBot : () => dispatch(addBot("test 123"))
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(FlowsContainer)

Resources