How to add loading effect in reactjs? - css

I'm creating a website using mern stack. In react files, I'm using many hooks, in useState hook, it takes some time to change and set new state. So, for that time it's showing data before changed state. I want to give some loading effect for the time till useState change the state and show data. What is the short and simple way to create that effect?

You can use something like this
import React, { useEffect } from "react";
import { getDatas } from "./getDatas";
import Datas from "../components/Datas";
import Loading from "../components/Loading";
export default function Component() {
const [datas, setDatas] = useState();
const [loading, setLoading] = useState(true);
useEffect(() => {
getDatas().then((res) => {
setDatas(res.datas);
setLoading(false);
});
}, []);
return (
<div>
{loading ? <Loading /> : <Datas />
</div>
);
}

Related

Using redux for editing fields without redux-forms

I am making a page which has many editable input fields.
I am using redux-toolkit and redux-thunk for this.
I am fetching data from api and put them into redux store. First render of component I want to reflect data in the store to the component's local state so that I can edit them and onSubmit of form, I am planning to re-put new values to store again.
Is this good approach?
Now it does not render anything and I think it because component rendering before api response arrives.
Is it possible without using redux-forms?
Component
import React, { useEffect, useState } from 'react'
import { Col, Row } from 'reactstrap'
import PreviewCaseTable from './refactor/PreviewCaseTable'
import { useDispatch, useSelector } from 'react-redux'
import { fetchCases, fetchCollections } from '../../../store/case/caseSlicer'
const TaskPreview2 = (props) => {
const dispatch = useDispatch()
const TaskStore = useSelector(store => store.Task)
const CaseStore = useSelector(store => store.Case)
const [cases, setCases] = useState(CaseStore.cases)
const [collections, setCollections] = useState(CaseStore.collections)
useEffect(() => {
dispatch(fetchCases({
taskId: TaskStore.selectedTask.taskId,
page: 0,
size: 100,
taskType: TaskStore.selectedTask.taskType
}))
dispatch(fetchCollections({ taskId: TaskStore.selectedTask.taskId }))
}, [])
return (
<div className="page-content">
<Row>
<Col>
{/*<UpdateWeightCard/>*/}
</Col>
<Col>
{/*<StrategyCard/>*/}
</Col>
</Row>
<Row>
{console.log("Cases:", cases)}
{cases.length > 0 && <PreviewCaseTable
cases={cases}
collections={collections}/>}
</Row>
</div>
)
}

Reference Error:Navigator not defined with nextjs

My code is like this:
import React, { useEffect } from 'react';
import alanBtn from '#alan-ai/alan-sdk-web';
const alanKey = my key;
const App = () => {
useEffect(() => {
alanBtn({
key: alanKey,
onCommand: ({ command }) => {
alert('This code was executed');
}
})
}, []);
return (
<div><h1>Alan AI News Application</h1></div>);
}
export default App;
But i am getting the error as:
Reference Error:Navigator not defined..
How to fix it?
Browser objects like window , navigator etc should be define in useEffect first before use.
const [pageURL, setPageURL] = useState("");
const [isNativeShare, setNativeShare] = useState(false);
useEffect(() => {
setPageURL(window.location.href);
if (navigator.share) {
setNativeShare(true);
}
}, []);
// Now, use can use pageURL , isNativeShare in code
This is not an issue with your Next.js code it's just the way you are supposed to call the alan-ai library.
Below is the solution that should work for you.
import React, { useEffect } from "react";
const alanKey = "my key";
function App() {
useEffect(() => {
const alanBtn = require("#alan-ai/alan-sdk-web");
alanBtn({
key: "myKey",
rootEl: document.getElementById("alan-btn")
});
}, []);
return (
<div>
<h1>Alan AI News Application</h1>
</div>
);
}
export default App;
Here is the discussion link for the same https://github.com/alan-ai/alan-sdk-web/issues/29#issuecomment-672242925.
Hope this solves your issue.
Happy Coding.

How can I test css properties for a React component using react-testing-library?

The philosophy behind the react-testing-library makes sense to me, but I am struggling to apply it to css properties.
For example, let's say I have a simple toggle component that shows a different background color when clicked:
import React, { useState } from "react";
import "./Toggle.css";
const Toggle = () => {
const [ selected, setSelected ] = useState(false);
return (
<div className={selected ? "on" : "off"} onClick={() => setSelected(!selected)}>
{selected ? "On" : "Off"}
</div>
);
}
export default Toggle;
.on {
background-color: green;
}
.off {
background-color: red;
}
How should I test this component? I wrote the following test, which works for inline component styles, but fails when using css classes as shown above.
import React from "react";
import { render, screen, fireEvent } from "#testing-library/react";
import Toggle from "./Toggle";
const backgroundColor = (element) => window.getComputedStyle(element).backgroundColor;
describe("Toggle", () => {
it("updates the background color when clicked", () => {
render(<Toggle />);
fireEvent.click(screen.getByText("Off"));
expect(backgroundColor(screen.getByText("On"))).toBe("green");
});
});
So that's not what unit or integration test frameworks do. They only test logic.
If you want to test styling then you need an end-to-end/snapshot testing framework like Selenium.
For making sure the styling is okay, I prefer snapshot testing. How about firing the event and taking snapshots for both states/cases. Here is what it would look like:
import React from 'react'
import {render} from '#testing-library/react'
it('should take a snapshot when button is toggled', () => {
const { asFragment } = render(<App />)
// Fire the event
expect(asFragment(<App />)).toMatchSnapshot()
})
});

Rerendering on async fetch with react-mobx

I'm trying to use mobx-rest with mobx-rest-axios-adapter and mobx-react, and I have trouble making the component rerender upon async data retrieval.
Here's my data model, in state/user.js:
import { Model } from 'mobx-rest';
class User extends Model {
url() {
return '/me';
}
}
export default new User();
This is the React component, in App.js:
import React from 'react';
import { inject, observer } from 'mobx-react';
import { apiClient } from 'mobx-rest';
import createAdapter from 'mobx-rest-axios-adapter';
import axios from 'axios';
import { compose, lifecycle, withProps } from 'recompose';
const accessToken = '...';
const API_URL = '...';
const App = ({ user }) => (
<div>
<strong>email:</strong>
{user.has('email') && user.get('email')}
</div>
);
const withInitialise = lifecycle({
async componentDidMount() {
const { user } = this.props;
const axiosAdapter = createAdapter(axios);
apiClient(axiosAdapter, {
apiPath: API_URL,
commonOptions: {
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
});
await user.fetch();
console.log('email', user.get('email'));
},
});
export default compose(
inject('user'),
observer,
withInitialise,
)(App);
It uses recompose to get the user asynchronously from an API in componentDidMount(), and once available the component is supposed to show the user email. componentDidMount() prints the email once available.
Finally this is index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';
import { Router } from 'react-router';
import App from './App';
import { user } from './state/user';
const documentElement = document.getElementById('ReactApp');
if (!documentElement) {
throw Error('React document element not found');
}
const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();
const stores = { user };
const history = syncHistoryWithStore(browserHistory, routingStore);
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<App />
</Router>
</Provider>,
documentElement,
);
My problem is that the component doesn't rerender once the user is retrieved and the email is available, although the console log shows that it is returned ok in the async request. I've tried playing around with mobx-react's computed, but no luck. Any ideas?
I think it will work if you change your compose order of App.js:
export default compose(
inject('user'),
withInitialise,
observer,
)(App);
According to the MobX official document,
Tip: when observer needs to be combined with other decorators or
higher-order-components, make sure that observer is the innermost
(first applied) decorator; otherwise it might do nothing at all.

TypeError: Object(...) is not a function (redux)

I am having a TypeError (TypeError: Object(...) is not a function) when I want to dispatch an action. I'm not using any middleware and don't know what I can do to solve it. I had this error already yesterday but somehow managed to solve it (i donk know how i did this)
This is the App.js:
import React from "react";
import { store } from "../store";
import { withdrawMoney} from "../actions";
const App = () => {
return (
<div className="app">
<div className="card">
<div className="card-header">
Welcome to your bank account
</div>
<div className="card-body">
<h1>Hello, {store.getState().name}!</h1>
<ul className="list-group">
<li className="list-group-item">
<h4>Your total amount:</h4>
{store.getState().balance}
</li>
</ul>
<button className="btn btn-primary card-link" data-amount="5000" onClick={dispatchBtnAction}>Withdraw $5,000</button>
<button className="btn btn-primary card-link" data-amount="10000" onClick={dispatchBtnAction}>Witdhraw $10,000</button>
</div>
</div>
</div>
);
}
function dispatchBtnAction(e) {
store.dispatch(withdrawMoney(e.target.dataset.amount));
}
export default App;
Here is the actioncreator:
function withdrawMoney(amount) {
return {
type: "ADD_TODO",
amount
}
}
If you need here is the reducer:
export default (state, action) => {
console.log(action);
return state
}
As you can see I'm a very new to redux but I'd like to know what mistake I make all the time when dispatching an action. Thanks
I believe the issue is that you aren't exporting the withdrawMoney function, so you aren't able to call it in the component that you're attempting to import into.
try:
export function withdrawMoney(amount) {
return {
type: "ADD_TODO",
amount
}
}
Another subtle mistake that will cause this error is what I tried to do, don't accidentally do this:
import React, { useSelector, useState ... } from 'react'
it should be:
import React, { useState } from 'react'
import { useSelector } from 'react-redux'
Try to install :
npm i react#next react-dom#next and run again
const mapStateToProps = state => ({
Bank: state.Bank,
});
function mapDispatchToProps(dispatch) {
return {
dispatch,
...bindActionCreators({ getBanks, addBank }, dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(BankComponent);
this worked like a Charm for me .
bit Late to party,
to me it was about casing.
export const addTodo = text => ({
type: ADD_TODO,
desc: text
});
export const removeTodo = id=> ({
type: REMOVE_TODO,
id: id
})
export const increaseCount = () => ({
type: INCREASE_COUNT
});
export const decreaseCount = () => ({
type: DECREASE_COUNT
})
when I renamed all those like
export const AddTodo = text => ({
type: ADD_TODO,
desc: text
});
export const RemoveTodo = id => ({
type: REMOVE_TODO,
id: id
})
export const IncreaseCount = () => ({
type: INCREASE_COUNT
});
export const DecreaseCount = () => ({
type: DECREASE_COUNT
})
it worked.
I spent hours debugging this, turns out I was doing this:
import React, { connect } from "react";
Instead of
import React from "react";
import { connect } from "react-redux";
It's weird the former didn't throw an error, but it will cause the problem!
First problem I see right off the bat is your reducer is not setup to do anything with the dispatched withdrawMoney action creator.
export default (state, action) => {
switch (action.type) {
case "ADD_TODO": {
return {
...state,
amount: action.amount,
};
}
default:
return state;
}
};
If this does not help, the code from your other files would be helpful.
It may not be the main issue, but it looks like you're not using the React-Redux library to work with the store. You can reference the store directly in your React components, but it's a bad practice. See my explanation for why you should be using React-Redux instead of writing "manual" store handling logic.
After updating react-redux to version 7.2.0+ I was receiving this error anytime I wrote:
const dispatch = useDispatch()
I stopped my application and re-ran it with npm start, and everything is working now.
I was using redux toolkit and for me the problem was an extra '}'
such that my 'reducers' object, in 'createSlice' function, already had a closing curly brace before my second reducer
and my 2nd reducer was actually outside the 'reducers' object,
making it not a reducer and hence not working even when you export or import it properly.
So the problem is not in your export or import, but actually where your function is defined.
This may be different for other users, but in my case this turned out to be the cause of this error.

Resources