React Hooks Equivalent of Flux Container - javascript

Refactoring a React class component previously using Flux to use React Hooks instead.
Previous component utilized getStores() and calculateState() in order to subscribe to store objects and update local state.
Is there a way to refactor the class component to a functional React component using React Hooks (useState, useEffect, etc?) to achieve the same subscription to store objects?
flux component example:
class exampleComponent extends React.Component {
static getStores() {
return [storeOne];
}
static calculateState() {
const someData = storeOne.getState();
return {
someData
};
}
}
goal(something like this that subscribes to the store):
function exampleComponent(props) {
const [storeData] = useState(storeOne.getState());
return (
<someElement
data={storeData}
>
</someElement>
);
}
Note: tried using useState as above but it does not subscribe to storeOne, so the component does not re-render when storeOne state changes. I'd like to be able to somehow subscribe to changes in storeOne so that the component will re-render when there are changes to storeOne.

Related

Can you use componentDidMount() on a React class that doesn't extend Component?

I've created my React class like such:
const MyMap = () => {
componentDidMount() {
...
}
return {
...
}
}
I realized that componentDidMount() is not being recognized and is not working. Is this because I didn't extend React.Component? Also, is there an alternative I can use for the React class I created?
you could use useEffect hook
useEffect(() => {
// write your logic here
}, []);
as they mention here
The Effect Hook, useEffect, adds the ability to perform side effects from a function component. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in React classes

How to use this.executeAction("someAction") in function based Component?

I've a class based component in which I'm calling the redux store through a action.
class App extends Component {
//Calling Constructor & setting State & other things
this.executeAction("someAction");
}
I want to know what would be the alternate for this in functional Component.
P.s:- I'm not sure if it is some library.
You can use useDipatch hook from react-redux
import { useDispatch } from 'react-redux'
function App() {
//Calling Constructor & setting State & other things
const dispatch = useDispatch()
dispatch("someAction")
}

Pass react-redux store and dispatch functions via props?

The following React component is given:
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { store, StoreState } from "../../redux/actions";
import { setBackgroundAction } from "../../redux/title.actions";
import "./Loader.scss";
interface ReduxProps {
bgClass: string;
}
interface Props extends ReduxProps {
bgChange?: boolean;
}
export default function Loader(props: Props) {
const [bgClassOld, setBgClassOld] = useState<string>("");
const dispatch = useDispatch();
useEffect(() => {
const { bgChange, bgClass } = props;
if (bgChange) {
setBgClassOld(bgClass);
dispatch(setBackgroundAction("bg-white"));
dispatch(setBackgroundAction(bgClassOld));
}
});
return (
<div className="d-flex">
<div className="loader">
<img src="/loadscreen.gif" />
</div>
</div>
);
}
// function mapping(state: StoreState): ReduxProps {
// return {
// bgClass: state.title.backgroundClass,
// };
// }
This is more a theoretical question to see how to actually do the following change:
The component Loader will be imported from another npm package (shared components).
My problem is that I have a redux state in the current implementation included (changed it from Class to Functional component, so thats mapping() is still in there).
As I only import the component in my "main" client, I will not have the whole redux setup in place. So I think I need to pass the store and the dispatch functions via props.
So should I create a prop store for my component, where I pass the redux store when I import the shared component?
Do I also create two props for each dispatch functions?
Does is make sense or would there be a better approach?
You generally shouldn't import the Redux store directly into components. The hooks allow your component to access whatever Redux store has been injected into the component tree by a <Provider>.
You also don't need to pass dispatch as a prop. Any component can call useDispatch(), and dispatch actions to whatever Redux store is actually being used.
If I understand your question, you're planning on importing this component into an existing app, and it sounds like that app is already configured to use (React-)Redux with a <Provider> at the top. If that's the case, then you don't have to do anything else special to make this work. Just call the React-Redux hooks in any of your components.

ReactWrapper::setProps() error when attempting to set Redux props in component for Jest/Enzyme test

I'm writing a unit test for a React component that is connected to Redux. One of the functions is the component is that it displays data if questionReducer.showquestions == true. I have attempted to re-create this functionality in the component by setting props with wrapper.setProps({ questionReducer: { showquestions: true } }). However, when I attempt this approach, I get the error:
ReactWrapper::setProps() expects a function as its second argument
How can I properly set the props for the connected Reducer in the component I am testing?
You should test the component alone, without being connected to Redux. That allows you to give props directly to component.
Example:
export class Component_ extends React.Component {
// your component logic here
}
const mapStateToProps = {
showQuestions: questionReducer.showquestions
}
const Component = connect(mapStateToProps)(Component_)
export default Component
And then in test you can just do this
const wrapper = shallow(<Component_ showQuestions={true} />

Using mobx store only outside of the react components render function

I have a react component that wraps a class that renders WebGL using three.js with the DOM and connects mobx store value and it changes with the class lifecycle methods.
The passed in mobx store is only used outside of the components render function in lifecycle functions (componentDidMount, componentDidUpdate, ..). Noticed that when the store changes, the component doesn't trigger a rerender. But I make a useless read within the render functions, such as in the example below passing a triggerRerenderListenerProp={this.props.store.debugSettings.showStats} prop to the div, the component becomes active only to store.debugSettings.showStats changes.
Is there a way of making the component listen to store changes wihtout using the store itself in the render function?
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
import MapPreview from 'classes/MapPreview';
import style from './Preview.css';
class Preview extends Component {
static propTypes = {
store: PropTypes.object.isRequired,
imageUrl: PropTypes.string.isRequired
};
constructor (props) {
super(props);
this.containerEl = null;
}
componentDidMount () {
const options = {
debugSettings: this.props.store.debugSettings,
previewSettings: this.props.store.previewSettings
};
this.preview = new MapPreview(this.containerEl, options);
this.preview.setImage(imageUrl);
}
componentDidUpdate () {
this.preview.updateOptions({
debugSettings: this.props.store.debugSettings,
previewSettings: this.props.store.previewSettings
});
}
render () {
return (
<div
className={style.normal}
ref={(el) => { this.containerEl = el; }}
triggerRerenderListenerProp={this.props.store.debugSettings.showStats}
/>
);
}
}
export default observer(Preview);
The problem ultimately has two issues:
One, React is designed to only re-render when state or prop data changes.
Two, with mobx-react, I'm pretty sure the whole point is that the component won't re-render unless you dereference an observable value.
So while your props are technically changing, React doesn't do a deep object comparison of the props.
What you might try is setting options as internal component state -- that might force a re-render even though nothing in the render method would have changed.
The caveat here is that the updated props (from your store) might be too deeply nested as to force React to re-render even while updating internal state. You might also need to piggy-back on shouldComponentUpdate();

Categories