NODE.JS
Social Media 만들기 - 10)Status, create post 창 만들기
dodop
2021. 7. 10. 19:44
home 화면에 post, status가 보이도록 설정하자 .
import React from 'react'
import { useSelector } from 'react-redux'
import Header from '../component/Haader'
import Status from '../component/Status'
import Post from '../component/Post'
function HomePage(props) {
const userLogin = useSelector(state => state.userLogin)
const userInfo = userLogin
if(!userInfo){
props.history.push('/login')
}
return (
<div className="home row mx-0">
<div className="col-md-8">
<Status/>
<Post />
</div>
<div className="col-md-4">
</div>
</div>
)
}
export default HomePage
post, status.js component들을 만들어준다.
status.js
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { STATUS } from '../_constants/globalConstants'
import Avatar from './Avatar'
function Status() {
const userLogin = useSelector(state => state.userLogin)
const {userInfo} = userLogin
const dispatch = useDispatch()
return (
<div className="status my-3 d-flex">
<Avatar src={userInfo.user.avatar} size="big-avatar"/>
<button className="statusBtn flex-fill" onClick={()=>dispatch({type:STATUS, payload:true})}>
{userInfo.user.username}, what are you thinking?
</button>
</div>
)
}
export default Status
status라는 새로운 상수, 리듀서를 만들어서 status값에 따라서 post를 생성하는 창이 뜨도록 설정하자.
globalConstants.js
export const STATUS = 'STATUS'
새로운 statusReducer를 생성해준다.
import { STATUS } from "../_constants/globalConstants";
export const statusReducer = (state=false, action)=>{
switch(action.type){
case STATUS:
return action.payload
default:
return state
}
}
store.js에 추가해준다.
status:statusReducer,
app.js에 만약 status스토어가 true라면 화면에 StatusModal이 뜨도록 설정하자.
App.js
const status = useSelector(state => state.status)
return (
<BrowserRouter>
<input type="checkbox" id="theme"/>
<div className="App">
<div className="main">
{userInfo && <Header/>}
{status && <StatusModal/>}
StatusModal을 작성하자.
여기서는 포스트를 업로드하는 컴포넌트를 만들 것이다.
캡쳐된 화면을 저장하는캔버스를 만드록, 화면을 저장하고,저장된 화면의 URL로 변환해서 저장된 화면을 이미지목록에 추가해준다.
import React, { useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { ALERT, STATUS } from '../_constants/globalConstants'
import Alert from './Alert'
function StatusModal() {
const userLogin = useSelector(state => state.userLogin)
const {userInfo} = userLogin
const theme = useSelector(state => state.theme)
const [content, setcontent] = useState('')
const dispatch = useDispatch()
const [Images, setImages] = useState([])
const [stream, setStream] = useState(false)
const [tracks, setTracks] = useState('')
const videoRef = useRef()
const canvasRef = useRef()
const handleChangeImages=(e)=>{
const files = [...e.target.files]
let newImages= []
let err = ''
files.forEach(file=>{
if(!file) return err = "File doesn't exist."
if(file.type !== 'image/jpeg' && file.type !=='image/png'){
return err = "Image format is incorrect."
}
return newImages.push(file)
})
if(err) dispatch({type:ALERT, payload:{error:err}})
setImages([...Images, ...newImages])
}
const deleteImage=(index)=>{
const newArr = [...Images]
newArr.splice(index, 1)
setImages(newArr)
}
const handleStream= () =>{
setStream(true)
// navigator.getWebcam = (navigator.getUserMedia || navigator.webKitGetUserMedia || navigator.moxGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia){
navigator.mediaDevices.getUserMedia({video:true})
.then(mediastream=>{
videoRef.current.srcObject = mediastream
videoRef.current.play()
const track = mediastream.getTracks()
setTracks(track[0])
}).catch(err=>console.log(err))
}
// else{
// navigator.getWebcam({video:true},
// function(stream){
// videoRef.current.srcObject = stream
// videoRef.current.play()
// const track = stream.getTracks()
// setTracks(track[0])
// }, function(){
// console.log("Web cam is not accesible.")
// })
// }
}
const handleCapture= () =>{
const width = videoRef.current.clientWidth;
const height = videoRef.current.clientHeight;
canvasRef.current.setAttribute("width", width)
canvasRef.current.setAttribute("height", height)
const ctx = canvasRef.current.getContext('2d')
ctx.drawImage(videoRef.current, 0, 0, width, height)
let URL = canvasRef.current.toDataURL()
setImages([...Images, {camera: URL}])
}
const handleStopStream= () =>{
tracks.stop()
setStream(false)
}
return (
<div className="status_modal">
<form>
<div className="status_header">
<h5 className="m-0">Create Post</h5>
<span onClick={()=>dispatch({type:STATUS, payload:false})}>×</span>
</div>
<div className="status_body">
<textarea name="content" value = {content} placeholder={`${userInfo.user.username}, what are you thinking?`} onChange={(e)=>setcontent(e.target.value)} />
<div className="show_images">
{
Images && Images.map((image, index)=>(
<div key={index} id="file_img">
<img src={image.camera? image.camera : URL.createObjectURL(image)}
alt="images" className="img-thumbnail rounded" style={{filter:theme? 'invert(1)':'inver(0)'}} />
<span onClick={()=>deleteImage(index)}>×</span>
</div>
))
}
</div>
{
stream &&
<div className="stream position-relative">
<video autoPlay muted style={{filter:theme? 'invert(1)':'inver(0)'}} ref={videoRef} width='100%' height='100%'></video>
<span onClick={handleStopStream}>×</span>
<canvas ref={canvasRef} style={{display:'none'}}></canvas>
</div>
}
<div className="input_images">
{
stream
? <i className="fas fa-camera" onClick={handleCapture}></i>
: <>
<i className="fas fa-camera" onClick={handleStream}></i>
<div className="file_upload">
<i className="fas fa-image"></i>
<input type="file" name="file" id="file_up" multiple accept="image/*" onChange={handleChangeImages}/>
</div>
</>
}
</div>
</div>
<div className="statue_footer">
<button className="btn btn-secondary w-100" type="submit">Post</button>
</div>
</form>
</div>
)
}
export default StatusModal
만약 카메라가 작동하지 않는다면,
Chrome: navigator.mediaDevices.getUserMedia is not a function
I'm on localhost and trying to use the MediaDevices.getUserMedia method in Chrome. I receive the error as titled. I understand that in Chrome it is only possible to use this function with a secure ...
stackoverflow.com
여길 참고해보자.