I have created hello component, I fetched API data in hello component checked browser http://localhost:3000/hello working fine, I want import inside of index.js component now I checking http://localhost:3000/. but data not coming what issues. could you please solve this issue please below my code
hello.js:
function Hello({ posts }) {
console.log(posts)
return (
<>
<ul>
{posts.map((post) =>(
<p>{post.name}</p>
))}
</ul>
</>
)
}
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries. See the "Technical details" section.
export async function getServerSideProps() {
// Call an external API endpoint to get posts.
// You can use any data fetching library
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
export default Hello
index.js
import React from 'react';
// import Layout from "../components/layout";
// import NavBar from "../components/navbar";
import Hello from './hello'
function Index() {
return (
<>
<Hello />
</>
)
}
export default Index;
I am pretty sure that you can only use getServerSideProps in a page component, not in an embedded component. So the solution to this is to import it in index.js and then send the data down to hello.js through props.
EDIT:
here is the code -->
hello.js
function Hello(props) {
return (
<>
<ul>
{props.posts.map((post) =>(
<p>{post.name}</p>
))}
</ul>
</>
)
}
export default Hello
index.js
import React from 'react';
import Hello from './hello'
function Index({posts}) {
return (
<>
<Hello posts={posts}/>
</>
)
}
export async function getServerSideProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
const posts = await res.json()
return {
props: {
posts
},
}
}
export default Index;
Related
I'm using an API for fetching data and it works just fine, by the way I'm using redux. when I refresh my project. I get this error. I also Have et loading so when data is not fetched, waits for it. I have no clue what to do.
This is the component which I used data in
import React, { useEffect } from 'react';
import { useSelector, useDispatch} from 'react-redux';
import { Link } from 'react-router-dom';
import millify from 'millify';
//Redux
import { fetchCoins } from "../../redux/coins/coinsAction";
const Homepage = () => {
const dispatch = useDispatch();
const {coins, loading } = useSelector(state => state.coinsState);
useEffect(() => {
dispatch(fetchCoins());
}, [])
console.log(coins);
return (
<>
{
loading ? <h1>Loading...</h1> :
<div>
<h2>Global Crypto Stats</h2>
<div>
<h5>Total Cryptcurrencies</h5>
<span>{millify(coins.data.stats.total)}</span>
<h5>Total Exchanges</h5>
<span>{millify(coins.data.stats.totalExchanges)}</span>
<h5>Total Market cap</h5>
<span>{millify(coins.data.stats.totalMarketCap)}</span>
<h5>Total 24h Volume</h5>
<span>{millify(coins.data.stats.total24hVolume)}</span>
<h5>Total Markets</h5>
<span>{millify(coins.data.stats.totalMarkets)}</span>
</div>
</div>
}
</>
);
};
export default Homepage;
When facing this issue, the main solution is to put "?" before each dots, it should look like this :
coins?.data?.stats?.total
Try this :)
Im trying to get some informations with api in my header. But not works. my codes.
export async function getStaticProps() {
console.log("test")
const res = await fetch(`https://api.namefake.com`)
const data = await res.json()
if (!data) {
return {
notFound: true,
}
}
return {
props: { data },
}
}
I put console.log in function for to test whether the function is runs. but nothing shows up in console. I tried this in _app.js and It worked but I want to use in Header. Im using layout for pages.
layout :
import Header from './header'
export default function Layout({ children }) {
return(
<>
<Header/>
{children}
</>
);
}
_app.js
import Layout from './layout'
function MyApp({ Component, pageProps }) {
<Layout>
<Component {...pageProps} />
</Layout>
</>
);
}
export default MyApp
functions like getStaticProps() getServerSideProps() are server side functions and does not get passed to client side and so it works only in page components (pages/index.js ) and it does not in components which usually get passed to client bundle
I have a need to fetch data from an API on component load, am using axios to fetch data, I need to save the response to the state and get back when the component load.
But i could do as am new to this.
My codes as below.
Sales.js : (This is where I fetch My components)
function SalesDesk() {
return (
<div>
<FoodScreen />
</div>
)}
export default SalesDesk;
FoodScreen.js (This is where i need to list my results to a variable, to map it later)
function FoodScreen() {
return(
<div className="sdFoodScreenMain">
{console.log(items)} // The results should be displayed here
</div>
)}
export default FoodScreen;
API.js (Here is where where i use my axios Router)
const API_URL = `https://jsonplaceholder.typicode.com/`; //Mock api for test purposes
export const GetAllItems = () => {
return (dispatch) => {
axios.get(API_URL)
.then(response => {
dispatch(allItemsList(response.data));
})
}
};
ItemsReducer.js (The reducer Logic)
const ItemsReducer =(state:Array = null, action) =>{
if (action.type === 'ALL_ITEMS') {
return GetAllItems ;
} else {
return state= null;
}
};
export default ItemsReducer
SalesAction.js (Action list)
export const allItemsList = () => {
return {
type: 'ALL_ITEMS'
};
};
All I need to do is fetch the the data from the API and display it in the console, when the component renders.so that I can display it in a map of div boxes for future purposes. Am new to both react and Redux, so ignore if any logic or implementation issues.
At first Router.js is a bad name(api.js etc), You should connect Sales.js to redux, using { connect } from 'react-redux'. See there https://redux.js.org/basics/usage-with-react and call action to fetch data in Sales.js
All I had to add an useDispatch on the component render, so it could fetch the data to the component on load.
import Reactfrom 'react'
import {useDispatch} from "react-redux";
import {GetAllItems} from 'API' //File containing the axios function
export function SalesDesk() {
const dispatch = useDispatch();
dispatch(GetAllItems())
return (
<div>
<FoodScreen />
</div>
)}
This helped me to fetch add add to state on component load.
All the examples I've seen of the new Context API in React are in a single file, e.g. https://github.com/wesbos/React-Context.
When I try to get it working across multiple files, I'm clearly missing something.
I'm hoping to make a GlobalConfiguration component (the MyProvider below) create and manage the values in the context, ready for any child component (MyConsumer below) read from it.
App.js
render() {
return (
<MyProvider>
<MyConsumer />
</MyProvider>
);
}
provider.js
import React, { Component } from 'react';
const MyContext = React.createContext('test');
export default class MyProvider extends Component {
render() {
return (
<MyContext.Provider
value={{ somevalue: 1 }}>
{this.props.children}
</MyContext.Provider >
);
}
}
consumer.js
import React, { Component } from 'react';
const MyContext = React.createContext('test');
export default class MyConsumer extends Component {
render() {
return (
<MyContext.Consumer>
{(context) => (
<div>{context.state.somevalue}</div>
)}
</MyContext.Consumer>
);
}
}
Unfortunately that fails with this in the console:
consumer.js:12 Uncaught TypeError: Cannot read property 'somevalue' of undefined
Have I completely missed the point? Is there documentation or an example of how this works across multiple files?
I think the problem that you are running into is that you are creating two different contexts, and trying to use them as one. It is the Context created by React.createContext that links Provider and Consumer.
Make a single file (I'll call it configContext.js)
configContext.js
import React, { Component, createContext } from "react";
// Provider and Consumer are connected through their "parent" context
const { Provider, Consumer } = createContext();
// Provider will be exported wrapped in ConfigProvider component.
class ConfigProvider extends Component {
state = {
userLoggedIn: false, // Mock login
profile: { // Mock user data
username: "Morgan",
image: "https://morganfillman.space/200/200",
bio: "I'm Mogranโso... yeah."
},
toggleLogin: () => {
const setTo = !this.state.userLoggedIn;
this.setState({ userLoggedIn: setTo });
}
};
render() {
return (
<Provider
value={{
userLoggedIn: this.state.userLoggedIn,
profile: this.state.profile,
toggleLogin: this.state.toggleLogin
}}
>
{this.props.children}
</Provider>
);
}
}
export { ConfigProvider };
// I make this default since it will probably be exported most often.
export default Consumer;
index.js
...
// We only import the ConfigProvider, not the Context, Provider, or Consumer.
import { ConfigProvider } from "./configContext";
import Header from "./Header";
import Profile from "./Profile";
import "./styles.css";
function App() {
return (
<div className="App">
<ConfigProvider>
<Header />
<main>
<Profile />
</main>
<footer>...</footer>
</ConfigProvider>
</div>
);
}
...
Header.js
import React from 'react'
import LoginBtn from './LoginBtn'
... // a couple of styles
const Header = props => {
return (
... // Opening tag, etc.
<LoginBtn /> // LoginBtn has access to Context data, see file.
... // etc.
export default Header
LoginBtn.js
import React from "react";
import Consumer from "./configContext";
const LoginBtn = props => {
return (
<Consumer>
{ctx => {
return (
<button className="login-btn" onClick={() => ctx.toggleLogin()}>
{ctx.userLoggedIn ? "Logout" : "Login"}
</button>
);
}}
</Consumer>
);
};
export default LoginBtn;
Profile.js
import React, { Fragment } from "react";
import Consumer from "./configContext"; // Always from that same file.
const UserProfile = props => {...}; // Dumb component
const Welcome = props => {...}; // Dumb component
const Profile = props => {
return (
<Consumer>
...
{ctx.userLoggedIn ? (
<UserProfile profile={ctx.profile} />
) : (<Welcome />)}
...
</Consumer>
...
Reading the source code of React-Context, they do
<MyContext.Provider value={{
state: this.state,
}}>
and
<MyContext.Consumer>
{(context) => <p>{context.state.age}</p>}
So if you do
<MyContext.Provider value={{ somevalue: 1 }}>
{this.props.children}
</MyContext.Provider>
You should get somevalue like that
<MyContext.Consumer>
{(context) => <div>{context.somevalue}</div>}
</MyContext.Consumer>
EDIT
What if you create a file called myContext.js with:
const MyContext = React.createContext('test');
export default MyContext;
and then import it like :
import MyContext form '<proper_path>/myContext';
As of right now, the two context you created in the files are not the same even thought the name is the same. You need to export the context that you created in one of the files, and use that through out.
so something like this, in your provider.js file:
import React, { Component } from 'react';
const MyContext = React.createContext();
export const MyContext;
export default class MyProvider extends Component {
render() {
return (
<MyContext.Provider
value={{ somevalue: 1 }}>
{this.props.children}
</MyContext.Provider >
);
}
}
then in your consumer.js file
import MyContext from 'provider.js';
import React, { Component } from 'react';
export default class MyConsumer extends Component {
render() {
return (
<MyContext.Consumer>
{(context) => (
<div>{context.somevalue}</div>
)}
</MyContext.Consumer>
);
}
}
I'm gonna throw my solution into the pot - it was inspired by #Striped and simply just renames the exports into something that makes sense in my head.
import React, { Component } from 'react'
import Blockchain from './cloudComputing/Blockchain'
const { Provider, Consumer: ContextConsumer } = React.createContext()
class ContextProvider extends Component {
constructor(props) {
super(props)
this.state = {
blockchain: new Blockchain(),
}
}
render() {
return (
<Provider value={this.state}>
{this.props.children}
</Provider>
)
}
}
module.exports = { ContextConsumer, ContextProvider }
Now it's easy to implement a ContextConsumer into any component
...
import { ContextConsumer } from '../Context'
...
export default class MyComponent extends PureComponent {
...
render() {
return (
<ContextConsumer>
{context => {
return (
<ScrollView style={blockStyle.scrollView}>
{map(context.blockchain.chain, block => (
<BlockCard data={block} />
))}
</ScrollView>
)
}}
</ContextConsumer>
)
}
I'm SO done with redux!
TLDR; Demo on CodeSandbox
My current method of solving the same problem is to use the Unstated library, which as a convenient wrapper around the React Context API. "Unstated" also provides dependency injection allow the creating of discrete instances of a container; which is handy for code reuse and testing.
How to Wrap a React/Unstated-Context as a Service
The following skeleton API Service holds state properties such as loggedIn, as well as two service methods: login() and logout(). These props and methods are now available throughout the app with a single import in each file that needs the context.
For example:
Api.js
import React from "react";
// Import helpers from Unstated
import { Provider, Subscribe, Container } from "unstated";
// APIContainer holds shared/global state and methods
class APIContainer extends Container {
constructor() {
super();
// Shared props
this.state = {
loggedIn: false
};
}
// Shared login method
async login() {
console.log("Logging in");
this.setState({ loggedIn: true });
}
// Shared logout method
async logout() {
console.log("Logging out");
this.setState({ loggedIn: false });
}
}
// Instantiate the API Container
const instance = new APIContainer();
// Wrap the Provider
const ApiProvider = props => {
return <Provider inject={[instance]}>{props.children}</Provider>;
};
// Wrap the Subscriber
const ApiSubscribe = props => {
return <Subscribe to={[instance]}>{props.children}</Subscribe>;
};
// Export wrapped Provider and Subscriber
export default {
Provider: ApiProvider,
Subscribe: ApiSubscribe
}
App.js
Now the Api.js module can be used as global provide in App.js:
import React from "React";
import { render } from "react-dom";
import Routes from "./Routes";
import Api from "./Api";
class App extends React.Component {
render() {
return (
<div>
<Api.Provider>
<Routes />
</Api.Provider>
</div>
);
}
}
render(<App />, document.getElementById("root"));
Pages/Home.js:
Finally, Api.js can subscribe to the state of the API from deep within the React tree.
import React from "react";
import Api from "../Api";
const Home = () => {
return (
<Api.Subscribe>
{api => (
<div>
<h1>๐ Home</h1>
<pre>
api.state.loggedIn = {api.state.loggedIn ? "๐ true" : "๐ false"}
</pre>
<button onClick={() => api.login()}>Login</button>
<button onClick={() => api.logout()}>Logout</button>
</div>
)}
</Api.Subscribe>
);
};
export default Home;
Try the CodeSandbox demo here: https://codesandbox.io/s/wqpr1o6w15
Hope that helps!
PS: Someone bash me on the head quick if I'm doing this the wrong way. I'd love to learn different/better approaches. - Thanks!
I am working on an app that functions almost entirely on the following route: /task/:taskId and there is nothing to render at the / route. Instead when you launch the app it should redirect to a task. Much like when you open slack and you are in a channel. Not on some page that says please select a channel. I cannot figure out where I'm suppose to load the tasks from the database.
Right now, I have a component that loads at / and in its componentDidMount method, I load the tasks from the database. Once the tasks are loaded, I do a history.push to redirect to the first task in the array of tasks from the database.
This all works great until I get redirected to a specific task and then refresh the page. That is, if I'm at /task/foobar and I refresh the page, the app doesn't load anything because tasks is only loaded from the database at /.
So what is the proper way to make sure that my data is loaded no matter which page I'm on?
EDIT - Adding some code for reference:
/routes.js - / uses Master.js and /task/:taskId uses TaskPage.js
import React from 'react';
import { Switch, Route } from 'react-router';
import App from './containers/App';
import Master from './containers/Master';
import TaskPage from './containers/TaskPage';
export default () => (
<App>
<Switch>
<Route exact path="/" component={Master} />
<Route path="/task/:taskId" component={TaskPage} />
</Switch>
</App>
);
/containers/Master.js - loadTasks is action creator that passes tasks data to tasks reducer. Also returns promise that resolves to the tasks data once loaded from local nedb database.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { loadTasks } from '../actions/tasks';
class Master extends Component {
componentDidMount() {
this.fetchData();
}
fetchData() {
this.props.loadTasks()
.then(tasks => {
const id = tasks[Object.keys(tasks)[0]]._id;
this.props.history.push(`/task/${id}`);
return true;
})
.catch(e => {
console.log('ERROR', e);
});
}
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
const mapStateToProps = (props, ownProps) => ({
taskId: ownProps.taskId
});
export default connect(mapStateToProps, {
loadTasks
})(Master);
/containers/TaskPage.js - Not much to see here. Just passing props to wrapped component Task which renders just fine as long as the app loads / first. If you hit /task/:taskId directly, nothing loads because the tasks data in the database only gets loaded to the redux store at /
import { connect } from 'react-redux';
import Task from '../components/Task';
const mapStateToProps = ({ tasks }, { match: { params: { taskId } } }) => ({
tasks,
taskId
});
export default connect(mapStateToProps)(Task);
Edit - I have removed my old answers in favor of what I think is a better approach based on some digging I've done.
I've seen a few things from Dan Abramov in a few places that make me think he'd do the data fetching inside of the component (not container) and he would use the componentDidMount lifecycle method to do so. The only piece I am not certain about is how best to decide if the app should display a loading status.
In Dan's and others' examples, they just check to see if state.loading is false and if state.items.length is 0. This only works if you always expect items to have data. But in my case, when you first launch the app, you will have no data in it so checking for 0 length doesn't really work. Instead I've added an initLoad property to the state.
I'm open to other ways of handling this if there are better methods.
routes.js
import React from 'react';
import { Switch, Route } from 'react-router';
import App from './containers/App';
import TaskPage from './containers/TaskPage';
export default () => (
<App>
<Switch>
<Route exact path="/" component={TaskPage} />
<Route path="/task/:taskId" component={TaskPage} />
</Switch>
</App>
);
TaskPage.js
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { loadTasks } from '../actions/tasks';
import Task from '../components/Task';
const mapStateToProps = ({ tasks }, { match: { params: { taskId } } }) => ({
tasks,
taskId,
});
const mapDispatchToProps = dispatch => ({
loadTasks: () => dispatch(loadTasks())
});
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Task));
Task.js
import React, { Component } from 'react';
import type { tasksType } from '../reducers/tasks';
import SidebarContainer from '../containers/SidebarContainer';
class Task extends Component {
props: {
loadTasks: () => any,
initForm: () => any,
taskId: string,
tasks: tasksType,
history: any
};
componentDidMount() {
this.fetchData();
}
fetchData() {
this.props.loadTasks()
.then(tasks => {
const taskId = this.props.taskId;
if (!taskId) {
const id = tasks[Object.keys(tasks)[0]]._id;
this.props.history.push(`/task/${id}`);
}
return true;
})
.catch(e => {
console.log('ERROR', e);
});
}
render() {
const { tasks, taskId, initForm } = this.props;
if (!tasks.initLoad || (tasks.loading && Object.keys(tasks.items).length < 1)) {
return <div>Loading</div>;
}
return (
<div id="wrapper">
<SidebarContainer taskId={taskId} />
<div id="main">
<div id="group-details">
{tasks.initLoad && Object.keys(tasks.items).length > 0 ?
(<div>Task details would go here...</div>) :
(<div>Please create a task</div>)
}
</div>
</div>
</div>
);
}
}
export default Task;